Formik场景下如何正确上传图片URL数组到Firestore
问题根因
两个核心问题导致图片链接未正常写入Firestore:
- 异步逻辑未正确等待:
getLinks函数循环执行时,没有等待uploadBytes和getDownloadURL的Promise执行完成就提前返回空数组。控制台打印对象时能看到链接是浏览器的延迟求值特性导致的——日志输出的是对象引用,你手动点击展开日志时异步push操作已经执行完成,但实际运行addDoc时,传入的imageArray还是空数组。 - 原始文件未存储:复现代码中的
selectMultipleFiles方法只保存了本地预览用的blob地址,没有存储上传需要的原始File对象,getLinks根本拿不到要上传的文件。 - 提示逻辑错误:原代码把成功提示放在
finally回调中,无论上传成功还是失败都会触发成功提示,不符合预期。
修复方案
按以下步骤调整代码即可:
- 新增state存储待上传的原始文件对象
- 修正文件选择逻辑,同时保存预览地址和原始File
- 重写
getLinks方法,用Promise.all等待所有文件上传、链接获取操作全部完成后再返回结果 - 调整Promise链结构,把成功提示移到上传完成的回调中,错误提示保留在catch分支
修复后核心代码
首先调整状态定义:
// 新增rawFiles存储原始上传文件 const [images, setImages] = useState([]) const [rawFiles, setRawFiles] = useState([])
修正文件选择方法:
const selectMultipleFiles = (e) => { const selectedFiles = Array.from(e.target.files); const previewUrls = selectedFiles.map(file => URL.createObjectURL(file)); setImages(previewUrls); // 保存原始文件供上传使用 setRawFiles(selectedFiles); };
重写getLinks函数,正确处理异步流程:
const getLinks = async () => { // 批量生成上传+取链接的异步任务 const uploadTasks = rawFiles.map(async (file) => { // 建议加时间戳/随机前缀避免同名文件覆盖,这里保留原路径逻辑 const storageRef = ref(storage, `/houses/${Date.now()}_${file.name}`); const snapshot = await uploadBytes(storageRef, file); return getDownloadURL(snapshot.ref); }); // 等待所有任务完成后返回完整链接数组 return Promise.all(uploadTasks); };
修正onSubmit逻辑:
onSubmit: async (values) => { getLinks() .then((imageArray) => { const newVals = { ...values, imageList: imageArray }; return newVals; }) .then(async (newValues) => { console.log(newValues); await addDoc(collection(db, "properties"), newValues); // 上传成功后再弹成功提示 setSnackAlert({ type: "success", message: "You provided values!! Congrats!", }); handleOpen(); }) .catch((err) => { console.error(err); setSnackAlert({ type: "error", message: "There was an error handling your request", }); handleOpen(); }); }
验证方法
修复后可以在addDoc调用前打印newValues.imageList.length,如果输出值和你选择的图片数量一致,说明异步逻辑正常,此时写入Firestore的文档就会携带完整的图片链接数组。
内容的提问来源于stack exchange,提问作者Brady Bott
相关产品推荐
相关产品推荐

