Firebase多文件上传自定义Hook:如何同时返回函数与状态?
解决方案
你当前的问题核心有两个:一是自定义Hook未返回上传状态,二是状态更新逻辑存在异步时序错误——循环结束就直接标记完成,但此时文件可能还在上传中,且错误状态会被后续的完成状态覆盖。以下是修复后的完整代码及关键改动说明:
import { ref, uploadBytesResumable } from "firebase/storage" import { proStorage } from "../firebase/config" import { v4 } from "uuid" import { useState } from "react" const useUploader = (data, foldername) => { // 初始化状态为null,区分未触发、完成、错误三种状态 const [upLoadcomplete, setUploadComplete] = useState(null) const uploadFiles = async () => { // 重置状态,避免上次上传结果干扰本次操作 setUploadComplete(null) try { // 将每个文件的上传任务包装为Promise,统一管理异步流程 const uploadPromises = data.map(file => { return new Promise((resolve, reject) => { const name = `${v4()}` const location = `${foldername}/${name}` const metadata = { customMetadata: { uuid_name: name, }, } const dataRef = ref(proStorage, location) const uploadTask = uploadBytesResumable(dataRef, file, metadata) uploadTask.on( "state_changed", (snapshot) => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100 console.log(`Upload is ${progress}% done`) switch (snapshot.state) { case "paused": console.log("Upload is paused") break case "running": console.log("Upload is running") break } }, (error) => { // 上传失败时终止Promise,触发catch逻辑 reject(new Error("Error with upload try again")) }, () => { // 上传成功时标记Promise完成 resolve(uploadTask.snapshot) } ) }) }) // 等待所有文件上传完成 await Promise.all(uploadPromises) // 全部上传成功后设置完成状态 setUploadComplete("Upload is now complete") } catch (error) { // 任意文件上传失败时设置错误状态 setUploadComplete(error.message) } } // 返回包含上传函数和状态的对象,供组件解构使用 return { uploadFiles, upLoadcomplete } } export default useUploader
关键改动说明
- 返回结构调整:不再仅返回上传函数,而是返回包含
uploadFiles和upLoadcomplete的对象,组件调用时可直接解构获取二者:const { uploadFiles, upLoadcomplete } = useUploader(files, "my-folder") - 异步流程修复:将每个上传任务包装为Promise,通过
Promise.all等待所有文件上传完成,避免循环结束就提前标记"完成" - 错误处理优化:只要有一个文件上传失败,就会触发catch逻辑设置错误状态,不会被后续的完成状态覆盖
- 状态重置:每次调用
uploadFiles时先将状态重置为null,避免上次上传结果干扰本次操作 - 拼写规范:统一变量名驼峰写法(如
setuploacomplete改为setUploadComplete),避免拼写错误导致的bug
组件使用示例
import useUploader from './useUploader' import { useState } from 'react' function UploadComponent() { const [files, setFiles] = useState([]) const { uploadFiles, upLoadcomplete } = useUploader(files, "user-uploads") const handleFileChange = (e) => { setFiles(Array.from(e.target.files)) } return ( <div> <input type="file" multiple onChange={handleFileChange} /> <button onClick={uploadFiles}>开始上传</button> {upLoadcomplete && <p>{upLoadcomplete}</p>} </div> ) }
内容的提问来源于stack exchange,提问作者Brian
相关产品推荐
相关产品推荐

