React+Firebase聊天应用报错:无文档可更新问题求助
我跟着YouTube教程用React和Firebase开发聊天应用,遇到了以下错误:
FirebaseError: No document to update: projects/local-eats-discovery/databases/(default)/documents/userChats/pmTVrOVTm1fVLn7WODarHl2WKir2.
另外需要说明的是,当前用户数据加载有延迟,控制台打印currentUser时,初始渲染为undefined,几秒后才会显示用户数据。相关代码如下:
import { useContext, useEffect, useState } from 'react'; import { db } from '../../Firebase/firebase.config'; import { collection, doc, getDoc, getDocs, query, serverTimestamp, setDoc, updateDoc, where } from 'firebase/firestore'; import { AuthContext } from '../../providers/AuthProviders/AuthProviders'; const SearchUser = () => { const [userName, setUserName] = useState(''); const [user, setUser] = useState(null); const [err, setErr] = useState(false); const [loding,setLoding] = useState(false) const { user: currentUser} = useContext(AuthContext); console.log(currentUser?.uid); useEffect(() => { if (!currentUser) { setLoding(true) } setLoding(false) },[currentUser]) const handelSearch = async () => { const q = query(collection(db, 'users'), where('displayName', '==', userName)); try { const querySnapshot = await getDocs(q); querySnapshot.forEach((doc) => { setUser(doc.data()); }); } catch (err) { setErr(true); } } const handelKey = (e) => { e.code === 'Enter' && handelSearch(); } const handelSelect = async () => { // here chacking the group chats in the firebase is exist or not , if not then creat { loding && <span> loading...</span> } const combinedId = currentUser.uid > user.uid ? currentUser.uid + user.uid : user.uid + currentUser.uid; try { const res = await getDoc(doc(db, 'chats', combinedId)); if (!res.exists()) { // create chat in chats collection await setDoc(doc(db, 'chats', combinedId), { message: [] }); } // Update userChats documents await updateDoc(doc(db, 'userChats', currentUser.uid), { [combinedId + '.userInfo']: { uid: user.uid, displayName: user.displayName, photoURL: user.photoURL }, [combinedId + '.date']: serverTimestamp() }); await updateDoc(doc(db, 'userChats', user.uid), { [combinedId + '.userInfo']: { uid: currentUser.uid, displayName: currentUser.displayName, photoURL: currentUser.photoURL }, [combinedId + '.date']: serverTimestamp() }); } catch (err) { console.log(err); } } return ( <div className="py-3 px-2"> <div className="w-full flex justify-start items-start gap-3"> <input type="text" className="border-gray-300 border-2 w-full px-3 py-2 rounded-md" onKeyDown={handelKey} onChange={e => setUserName(e.target.value)} /> </div> {err && <span>User not found</span>} {user && <div className='flex justify-start items-start gap-3 p-5 drop-shadow-md bg-gray-100 mt-4' onClick={handelSelect}> <div><img src={user?.photoURL} alt="" className='w-20'/></div> <div> <h4 className='text-2xs font-bold'>{user?.displayName}</h4> <p className='text-sm text-gray-500'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ea harum veniam aspernatur voluptatem ex non ....</p> </div> </div> } </div> ); }; export default SearchUser;
1. 核心错误:userChats文档不存在
updateDoc仅能更新已存在的Firestore文档,你尝试更新的userChats/{currentUser.uid}文档尚未创建,因此触发报错。
替换原有updateDoc逻辑,改用setDoc并添加merge: true参数——该参数会自动处理文档不存在的情况:若文档不存在则创建,若存在则仅更新指定字段,不会覆盖整个文档:
// 替换handelSelect中更新userChats的两段代码 await setDoc(doc(db, 'userChats', currentUser.uid), { [combinedId + '.userInfo']: { uid: user.uid, displayName: user.displayName, photoURL: user.photoURL }, [combinedId + '.date']: serverTimestamp() }, { merge: true }); await setDoc(doc(db, 'userChats', user.uid), { [combinedId + '.userInfo']: { uid: currentUser.uid, displayName: currentUser.displayName, photoURL: currentUser.photoURL }, [combinedId + '.date']: serverTimestamp() }, { merge: true });
2. 修复用户加载延迟的潜在问题
当前用户数据加载延迟,初始currentUser为undefined,可能导致handelSelect中访问currentUser.uid报错,同时原有加载状态逻辑存在问题:
优化加载状态逻辑
原有useEffect会在设置loading: true后立刻设为false,修改为根据currentUser存在状态直接控制:
useEffect(() => { setLoding(!currentUser); // 用户未加载时显示加载中,加载完成后结束 }, [currentUser])
防止未加载完成时触发操作
在handelSelect开头增加校验,避免用户数据未加载完成时执行后续逻辑:
const handelSelect = async () => { if (!currentUser || !user) return; // 用户数据未就绪时直接返回 // 原有逻辑... }
另外,你在handelSelect函数内写的{ loding && <span> loading...</span> }是无效代码(函数逻辑中无法直接渲染JSX),建议将加载提示放到组件的return结构中,或者用状态控制点击区域的禁用状态。
3. 其他小优化
handelSearch中如果查询到多个同名用户,只会将最后一个用户存入state,建议处理为数组展示或提示用户重名情况;- 搜索操作可添加loading状态,避免重复点击触发多次查询。
内容的提问来源于stack exchange,提问作者Asif Khan

