构建您自己的 Hook 来将图像上传到 Firebase 让我们开始吧

2025-06-07

构建您自己的 Hook 以将图像上传到 Firebase

让我们开始吧

在开始构建自定义 React Hook 之前,我想提醒你,你应该对 React Hook 的基本知识有充分的了解。如果你不熟悉这些基础知识,可以从这里开始,然后再回到这里。


让我们开始吧

为了构建自定义钩子,您应该记住以下几点...请在此处阅读所有规则。

现在我们已经介绍了基础知识并准备构建我们自己的自定义 Hook。

我们将构建一个自定义钩子,它将以文件作为道具并将其上传到 Firebase 存储,同时返回上传进度,最后返回可存储在数据库中或用作 img src 的公共 URL。

创建 React 项目

创建你的 React 项目并进入项目目录

npx create-react-app <your app name here>
cd <your app name here>
Enter fullscreen mode Exit fullscreen mode

然后启动你的反应应用程序

npm run start
Enter fullscreen mode Exit fullscreen mode

现在您应该有一个如下所示的样板 React 项目。

替代文本

清理并开始构建 UI

清理后,您的文件结构如下所示

替代文本

清理所有样板代码并添加一个带有文件类型输入的表单,App.js并添加方法handleChange来处理用户选择文件时的事件。
App.js添加这些东西之后......

import React, { useState } from "react";
import "./App.css";

function App() {
    const [file, setFile] = useState(null);
    const [error, setError] = useState(null);

    const types = ["image/png", "image/jpeg", "image/jpg"];

    const handleChange = (e) => {
        let selectedFile = e.target.files[0];

        if (selectedFile) {
            if (types.includes(selectedFile.type)) {
                setError(null);
                setFile(selectedFile);
            } else {
                setFile(null);
                setError("Please select an image file (png or jpg)");
            }
        }
    };

    return (
        <div className="App">
            <form>
                <label>
                    <input type="file" onChange={handleChange} />
                    <span>Upload Image</span>
                </label>
            </form>
        </div>
    );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

我还添加了一个仅接受图像文件的过滤器,并使用useState钩子将所选文件的file状态和所有错误error状态存储在其中。
现在你的应用应该看起来像这样……

替代文本

创建 Firebase 项目

转到Firebase 控制台并使用您的 Google 帐户登录,然后单击添加项目

替代文本

然后给你的项目命名并继续

替代文本

禁用谷歌分析并创建项目

替代文本

使用 Firebase 注册您的应用

将您的应用添加到 Firebase。

替代文本

为您的应用命名并注册。Firebase 将为您提供该应用的凭据,其内容类似于以下对象。

var firebaseConfig = {
    apiKey: "AIzaSyDo5UUe86THOjczUAhytr7yu67FlLVmpj2E",
    authDomain: "new-project.firebaseapp.com",
    databaseURL: "https://new-project.firebaseio.com",
    projectId: "new-project",
    storageBucket: "new-project.appspot.com",
    messagingSenderId: "509872254322",
    appId: "1:509872254322:web:d63d977d86c734nu829e12f"
  };
Enter fullscreen mode Exit fullscreen mode

复制 firebase 给您的对象,然后转到您的项目目录。

将您的应用与 Firebase 连接

firebase在文件夹内创建一个新文件夹并命名。在文件夹src创建一个文件,并将对象粘贴到文件中。config.jsfirebasefirebaseConfig

现在安装firebasenpm 包。从根目录执行以下命令。

npm i firebase
Enter fullscreen mode Exit fullscreen mode

现在通过在config.js文件中导入 firebase 包并导出storage方法来初始化 firebase。

import firebase from "firebase";
import "firebase/storage";

const firebaseConfig = {
    apiKey: "AIzaSyDo5UUe86THOjczUAhytr7yu67FlLVmpj2E",
    authDomain: "new-project.firebaseapp.com",
    databaseURL: "https://new-project.firebaseio.com",
    projectId: "new-project",
    storageBucket: "new-project.appspot.com",
    messagingSenderId: "509872254322",
    appId: "1:509872254322:web:d63d977d86c734nu829e12f"
 };

// Initialize Firebase
firebase.initializeApp(firebaseConfig);

const projectStorage = firebase.storage();

export { projectStorage };
Enter fullscreen mode Exit fullscreen mode

在 Firebase 控制台中设置存储

单击左侧栏中的“存储”链接,然后单击“开始”

替代文本

然后单击下一步完成

现在我们需要更改,rules以便每个人都可以从您的 Firebase 存储中read访问。 为此,请导航至“规则”选项卡。write

替代文本

然后删除当前规则,并将以下规则粘贴到规则编辑器中。然后确认Publish新规则正确无误。

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

现在我们已经准备好将图像从我们的应用程序上传到 Firebase。

最后让我们创建自定义钩子

src在文件夹名称中创建一个新文件夹。然后在文件夹hooks创建一个新文件。这将是我们用于将图像上传到 Firebase 存储的自定义钩子。useStorage.jshooks

最终的文件夹结构将如下所示。

替代文本

我们将使用两个基本钩子useStateuseEffect我们的自定义钩子。

  • 我们需要创建一个,并在我们的文件reference to the Firebase storage中初始化和导出它。config.js
  • 然后使用put()该参考上的方法上传图像。
  • 该方法会在每次状态变化时put()返回一个快照。我们可以使用此快照来跟踪上传进度(以百分比表示) 。snap
  • 最后,我们将从上传的图像中获取公共 URL。

因此在文件中添加以下代码useStorage.js

import { useState, useEffect } from "react";

import { projectStorage } from "../firebase/config";

export const useStorage = (file) => {
    const [progress, setProgress] = useState(0);
    const [error, setError] = useState(null);
    const [url, setUrl] = useState(null);

    // runs every time the file value changes
    useEffect(() => {
        if (file) {
            // storage ref
            const storageRef = projectStorage.ref(file.name);

            storageRef.put(file).on(
                "state_changed",
                (snap) => {
                    // track the upload progress
                    let percentage =
                        Math.round(
                        (snap.bytesTransferred / snap.totalBytes) * 100
                    );
                    setProgress(percentage);
                },
                (err) => {
                    setError(err);
                },
                async () => {
                    // get the public download img url
                    const downloadUrl = await storageRef.getDownloadURL();

                    // save the url to local state
                    setUrl(downloadUrl);
                }
            );
        }
    }, [file]);

    return { progress, url, error };
};

Enter fullscreen mode Exit fullscreen mode

我们在钩子中添加了所有逻辑useEffect,并将其添加file为依赖项。这样,每当文件发生更改时,我们的钩子就会重新运行。
最后,我们导出了progressurlerror

将钩子集成到我们的组件中

useStorage现在,我们可以在组件中导入该钩子,并将其与所选文件一起使用。集成该钩子后,
我们还可以显示进度。
App.jsuseStorage

import React, { useState } from "react";
import "./App.css";

import { useStorage } from "./hooks/useStorage";

function App() {
    const [file, setFile] = useState(null);
    const [error, setError] = useState(null);

    const types = ["image/png", "image/jpeg", "image/jpg"];

    const handleChange = (e) => {
        let selectedFile = e.target.files[0];

        if (selectedFile) {
            if (types.includes(selectedFile.type)) {
                setError(null);
                setFile(selectedFile);
            } else {
                setFile(null);
                setError("Please select an image file (png or jpg)");
            }
        }
    };

    // Getting the progress and url from the hook
    const { progress, url } = useStorage(file);

    return (
        <div className="App">
            <form>
                <label>
                    <input type="file" onChange={handleChange} />
                    <span>Upload Image</span>
                </label>
            </form>

            {error && <p>{error}</p>}
        </div>
    );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

现在我们可以访问文件的progressand了。我们可以用它来给用户一些反馈,然后在上传完成时url显示图片。在显示错误的段落标签之后的根目录下 添加这些内容。 现在我们的应用也会显示进度和图片了。url
htmldiv

{file && <p>{progress}% uploaded</p>}
{url && (
          <p>
             <b>File url: </b>
             <a href={url}>{url}</a>
          </p>
)}
{url && <img src={url}></img>}
Enter fullscreen mode Exit fullscreen mode

我们App.js现在...

import React, { useState } from "react";
import "./App.css";

import { useStorage } from "./hooks/useStorage";

function App() {
    const [file, setFile] = useState(null);
    const [error, setError] = useState(null);

    const types = ["image/png", "image/jpeg", "image/jpg"];

    const handleChange = (e) => {
        let selectedFile = e.target.files[0];

        if (selectedFile) {
            if (types.includes(selectedFile.type)) {
                setError(null);
                setFile(selectedFile);
            } else {
                setFile(null);
                setError("Please select an image file (png or jpg)");
            }
        }
    };

    // Getting the progress and url from the hook
    const { progress, url } = useStorage(file);

    return (
        <div className="App">
            <form>
                <label>
                    <input type="file" onChange={handleChange} />
                    <span>Upload Image</span>
                </label>
            </form>

            {error && <p>{error}</p>}
            {file && <p>{progress}% uploaded</p>}
            {url && (
                <p>
                    <b>File url: </b>
                    <a href={url}>{url}</a>
                </p>
            )}
            {url && <img src={url}></img>}
        </div>
    );
}

export default App;
Enter fullscreen mode Exit fullscreen mode
  • 所以现在我们已经成功创建了自己的自定义钩子。
  • 将其集成到我们的组件中。
  • 并且还显示进度并在上传完成后显示图像。
  • 如果需要,您还可以将 URL 存储在数据库中。

您可以在这里实时查看该应用。快去看看吧。

你也可以在我的Github Reposource code查看完整代码。使用代码前请确保将其替换。否则将无法使用。my firebase credentialsyour credentials


在网络上找到我🕸:

文章来源:https://dev.to/soumyadey/build-your-own-hook-for-uploading-images-to-firebase-3bg9
PREV
抢先一睹 Ruby 的新调试器!
NEXT
在 JavaScript 中编写异步构造函数的正确方法 异步构造函数???构造函数速成课程 解决方法 #1:延迟初始化 解决方法 #2:防御性编程 解决方案:静态异步工厂函数!实践总结