React中Firestore报Invalid document reference错误的排查与解决
问题分析与解决
你的推测是否正确?
不正确。渲染时调用setScore只是提前暴露了代码中的Firebase API使用错误,并非问题根源。
问题根源
Firestore API 使用错误:
你在setScore函数中用doc(db, "Leaderboard")作为addDoc的参数,但doc()函数需要的是集合路径+文档ID(路径段数为偶数,比如"Leaderboard/user123"),单独的"Leaderboard"是集合路径,段数为1,不符合文档引用的要求。而addDoc的正确用法是传入集合引用,它会自动生成唯一的文档ID。useEffect 触发时机不当:
组件初始渲染时isAnonymous为false,useEffect会立即执行setScore,此时user是空字符串,既不符合业务需求(应该在用户点击登录后才提交分数),还会触发无效的Firebase请求。
解决方案
1. 修正setScore的Firebase调用
将doc(db, "Leaderboard")改为collection(db, "Leaderboard"),因为addDoc需要接收集合引用:
const setScore= async(timeprop, userprop)=>{ console.log(timeprop, userprop) await addDoc(collection(db, "Leaderboard"), { name: userprop, time: timeprop, }) }
2. 调整useEffect的触发逻辑
只在用户完成登录(isAnonymous变为true)且user有有效值时,才提交分数并获取排行榜:
useEffect(()=>{ // 仅当用户登录且用户名非空时执行操作 if(isAnonymous && user){ setScore(time, user) getLeaderboard() } }, [isAnonymous, user, time])
3. 优化登录校验(可选)
避免用户提交空用户名,在登录函数中增加校验:
const loginAnonymously = () =>{ if(!username.trim()){ alert("请输入用户名") return } setUser(username.trim()) setIsAnonymous(true) }
4. 修正排行榜渲染的key(可选)
若存在同名用户,用文档ID作为key更可靠,修改getLeaderboard函数:
async function getLeaderboard(){ const q = query(collection(db, "Leaderboard")); const chacSnapShot = await getDocs(q); // 保留文档ID用于渲染key const char = chacSnapShot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setLeaderboard(char) }
渲染时使用data.id作为key:
<div key={data.id} className="user-container"> <p className="username">{data.name}</p> <p className="userdata">{data.time}</p> </div>
内容的提问来源于stack exchange,提问作者Habizsabi
相关产品推荐
相关产品推荐

