You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 09:40:35