React接入Firebase上传图片后写入Firestore报imgURL未定义如何解决
问题解决方法
错误原因
- Firebase Storage上传属于异步操作,你当前代码中Firestore写入逻辑放在上传逻辑外部,会在上传触发后立刻执行,此时上传还未完成,
imgURL还未被赋值自然是undefined - React的状态更新方法
setImgURL本身也是异步的,就算上传完成回调触发后执行了setImgURL(url),你也无法在当前函数作用域立刻拿到更新后的imgURL值
修复方案
直接把Firestore写入逻辑整体移动到getDownloadURL的成功回调中,直接使用回调返回的url参数即可,不需要依赖state存储的imgURL,修改后的代码如下:
import React, { useState } from "react"; import "../mainTab.css"; import "./addScreen.css"; import firebase, { storage } from "../firebase"; const AddScreen = () => { const db = firebase.firestore(); // 给所有状态设置初始空值,避免其他字段也出现undefined报错 const [cat, setCat] = useState(""); const [course, setCourse] = useState(""); const [name, setName] = useState(""); const [price, setPrice] = useState(""); const [descrip, setDescrip] = useState(""); const [image, setImage] = useState(null); const onSubmitHandler = (event) => { event.preventDefault(); // 增加非空校验,避免未选图片直接提交报错 if(!image) return alert("请先选择要上传的图片"); const ref = storage.ref(`/images/${image.name}`); const uploadTask = ref.put(image); uploadTask.on("state_changed", console.log, console.error, () => { ref.getDownloadURL().then((url) => { // 拿到图片URL后再执行数据库写入操作 const data = { name: name, price: price, cat: cat, course: course, decription: descrip, image: url, // 直接使用回调返回的url,不需要走状态读取 }; db.collection("menu") .doc(course.toString()) .collection(name.toString()) .add(data) .then(() => { alert("menu item is posted"); // 写入成功后再清空表单 setName(""); setPrice(""); setCat(""); setCourse(""); setImage(null); setDescrip(""); }) .catch((error) => alert("error: " + error)); }); }); };
额外优化建议
- 可以增加一个加载状态,上传过程中禁用提交按钮,避免用户重复点击提交
- 可以在上传失败的回调中增加对应的错误提示,优化用户体验
内容的提问来源于stack exchange,提问作者Anirudh Saladi
相关产品推荐
相关产品推荐

