React Native集成Firebase更新用户资料时无文档可更新错误解决
React Native + Firebase 更新用户资料报错:No document to update
问题描述
错误信息:
Unhandled promise rejection: FirebaseError: No document to update: projects/donate-83e96/databases/(default)/documents/触发场景:登录后进入用户资料页面填写信息,点击「更新」按钮时出现该错误。Firestore免费试用到期前功能正常,到期后出现此问题。
用户提供的代码:
import {db,auth} from '../../firebase' const EditProfile=({navigation})=>{ const [image, setImage] = useState(null); const [uploading,setUploading] = useState(false) const [userData, setUserData] = useState(null); {/*retrieve data from firestore*/} React.useEffect(()=>{ const getUserData = async()=>{ db.collection("users") .doc(auth.currentUser?.uid) .get() .then(snap => { setUserData(snap.data()); }); } getUserData(); },[]) const updateProfile = async()=>{ let imgUrl = await uploadImage(); if(imgUrl == null && userData.userImg){ imgUrl = userData.userImg } db.collection("users") .doc(auth.currentUser.uid) .update({ name: userData.name, email: userData.email, phone: userData.phone, address: userData.address, userImg:userData.imgUrl }) } {/*upload Image to firebase sotrage*/} const uploadImage = async ()=>{ if(image == null){ return ""; } const blob = await new Promise((resolve, reject)=>{ const xhr = new XMLHttpRequest(); xhr.onload = function (){ resolve(xhr.response) }; xhr.onerror = function (){ reject( new TypeError("Network request failed")) }; xhr.responseType = "blob" xhr.open("GET",image,true) xhr.send(null) }); const ref = firebase.storage().ref().child("images/" + new Date().toISOString()) const snapshot = ref.put(blob) snapshot.on( firebase.storage.TaskEvent.STATE_CHANGED, ()=>{ setUploading(true) }, (error)=>{ setUploading(false) console.log(error) blob.close(); return ; }, ()=>{ snapshot.snapshot.ref.getDownloadURL().then((url)=>{ setUserData({...userData, imgUrl: url}) setUploading(false); // Alert.alert('Profile Updated', 'You profile Updated Successfully..!') console.log('donwload:', url) blob.close() return null }) } ) } function renderDetails(){ return( <View> {/*edit name*/} <View> <TextInput placeholder="Name" placeholderTextColor='#66666666' autoCorrect={false} value={userData ? userData.name : ''} onChangeText={(txt) => setUserData({...userData, name: txt})} style={{ paddingLeft:5, color:'#05375a' }} /> </View> {/*edit email*/} <View> <TextInput placeholder="Email" placeholderTextColor='#66666666' keyboardType="email-address" autoCorrect={false} value={userData ? userData.email : ''} onChangeText={(txt) => setUserData({...userData, email: txt})} style={{ paddingLeft:5, color:'#05375a' }} /> </View> {/* edit phone number and the address same textInput as name and email*/} {/*Update Button*/} {!uploading ? <View> <AppButton label="Update" onPress={updateProfile} /> </View> :<UploadProgress /> }
问题分析与修复方案
1. 优先检查Firestore安全规则(核心原因)
Firestore免费试用到期后,默认安全规则会被调整为禁止未授权写入,甚至完全锁死写入操作。
- 打开Firebase控制台 → 进入Firestore数据库 → 切换到「规则」标签页
- 替换为允许认证用户修改自己文档的规则:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read, update, delete: if request.auth != null && request.auth.uid == userId; allow create: if request.auth != null; } } }
注意:不要用
allow read, write: if true;这种宽松规则,会导致数据泄露风险。
2. 替换update()为set({merge: true})
update()要求文档必须存在,如果用户文档被误删或未初始化,就会触发「No document to update」错误。改用set并开启merge选项,文档不存在时会自动创建,存在时合并更新字段:
// 把updateProfile里的update代码改成下面这样 await db.collection("users") .doc(auth.currentUser.uid) .set({ name: userData.name, email: userData.email, phone: userData.phone, address: userData.address, userImg: imgUrl // 这里要改成前面的imgUrl变量,不是userData.imgUrl }, { merge: true })
3. 修复uploadImage函数的返回值问题
当前uploadImage没有正确返回图片URL,导致imgUrl始终为空,而且字段名不统一(代码里既有imgUrl又有userImg)。修改成Promise风格,确保返回URL:
const uploadImage = async () => { if (image == null) { return userData?.userImg || ""; // 没有新图片时直接返回现有头像URL } return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.onload = function () { const blob = xhr.response; const ref = firebase.storage().ref().child("images/" + new Date().toISOString()); const snapshot = ref.put(blob); snapshot.on( firebase.storage.TaskEvent.STATE_CHANGED, () => setUploading(true), (error) => { setUploading(false); console.log(error); blob.close(); reject(error); }, () => { snapshot.snapshot.ref.getDownloadURL().then((url) => { setUserData(prev => ({...prev, userImg: url})); // 统一用userImg字段 setUploading(false); blob.close(); resolve(url); // 返回图片URL }); } ); }; xhr.onerror = function () { reject(new TypeError("Network request failed")); }; xhr.responseType = "blob"; xhr.open("GET", image, true); xhr.send(null); }); }
4. 完善updateProfile的异常处理
加上用户未登录判断,以及数据库操作的错误捕获:
const updateProfile = async()=>{ if (!auth.currentUser) { Alert.alert('提示', '用户未登录'); return; } let imgUrl; try { imgUrl = await uploadImage(); } catch (err) { console.log('图片上传失败', err); imgUrl = userData?.userImg; } try { await db.collection("users") .doc(auth.currentUser.uid) .set({ name: userData?.name || "", email: userData?.email || "", phone: userData?.phone || "", address: userData?.address || "", userImg: imgUrl }, { merge: true }); Alert.alert('成功', '资料更新完成'); } catch (err) { console.log('更新失败', err); Alert.alert('错误', '更新资料时出错,请稍后重试'); } }
5. 检查Firebase配额使用情况
免费试用到期后,Firestore的写入配额会大幅降低,如果超出配额也会导致操作失败。进入Firebase控制台 → 使用情况 → Firestore,确认是否超出写入次数限制。
内容的提问来源于stack exchange,提问作者Bashamlan Salem
相关产品推荐
相关产品推荐

