React中FirebaseError: DocumentReference.set()调用异常求助
解决Firebase图片上传后异步写入Firestore的问题
这个问题我太熟悉了——核心就是异步操作的执行顺序没处理对:你调用uploadImage后立刻就去写Firestore,但这时候图片还在上传过程中,downloadImage状态还没更新,自然会是undefined。咱们一步步把它改好:
第一步:改造uploadImage函数,让它返回下载链接的Promise
原来的uploadImage虽然标了async,但内部用了.then()链式调用,而且没有返回最终的下载链接,导致外部没法等待它完成。咱们把它改成纯async/await风格,并且明确返回下载链接:
const uploadImage = async (uri, imageName) => { try { const response = await fetch(uri); const blob = await response.blob(); const storageRef = firebase.storage().ref().child(`images/${imageName}`); // 等待图片上传完成 await storageRef.put(blob); // 等待获取下载链接并返回 const downloadUrl = await storageRef.getDownloadURL(); console.log(`File available at ${downloadUrl}`); setDownload(downloadUrl); // 如果你还需要保留这个状态的话 return downloadUrl; // 关键:把下载链接返回给调用者 } catch (error) { setRefreshing(false); Alert.alert("An error occured", "Please try again later"); throw error; // 抛出错误,让外部可以捕获处理 } }
第二步:修改handleSubmit,等待图片上传完成再写Firestore
因为要等待uploadImage完成,所以handleSubmit要改成async函数,用await获取下载链接后,再传入Firestore的set方法:
const handleSubmit = useCallback(async () => { if (postImage !== undefined) { const fileExtention = postImage[0].split('.').pop(); const fileName = `${uniqid}.${fileExtention}`; // 关键:等待图片上传完成,拿到有效的下载链接 const imageUrl = await uploadImage(postImage, fileName); // 现在有了可靠的imageUrl,再写入Firestore await firebase.firestore() .collection('Posts') .doc(uniqid) .set({ id: currentUser, name: postName[0], image: imageUrl, // 直接用刚拿到的返回值,比依赖状态更可靠 }); } }, [postImage, uniqid, currentUser, postName]); // 别忘了给useCallback加上正确的依赖项
为什么这样改能解决问题?
uploadImage现在返回一个Promise,只有当图片上传完成、拿到下载链接时才会resolve,外部用await就能确保后续代码在异步操作完成后执行。- 直接使用
uploadImage返回的imageUrl比依赖状态更可靠,因为React状态更新是异步的,即使调用了setDownload,也不能立刻在下一步拿到更新后的值。 - 给
useCallback补充依赖项,避免闭包导致的变量旧值问题。
这样修改后,就能保证只有图片上传完成、拿到有效下载链接后,才会往Firestore里写入数据,再也不会出现image字段为undefined的错误啦!
内容的提问来源于stack exchange,提问作者Dilhan Bhagat
相关产品推荐
相关产品推荐

