onSnapshot在onAuthStateChanged中返回错误用户数据问题排查
问题
在React中使用Firebase时,切换账号后更新当前用户(比如添加新关注),onSnapshot会返回错误的用户数据(显示我关注的用户,而非更新后的当前用户),刷新页面后数据才恢复正常。控制台打印的user.uid与doc.data().uid一致,但React控制台显示的用户数据却不符,getAuth()能保持正确的登录用户,推测是缓存或订阅清理问题。
监听用户更新的函数
useEffect(() => { let unsubscribe; onAuthStateChanged(auth, (user) => { if (user) { const docRef = doc(db, "users", user.uid); unsubscribe = onSnapshot(docRef, (doc) => { console.log(user.uid); console.log(doc.data().uid); setUserState(doc.data()); }); } else { setUserState(false); } }); return () => { if (unsubscribe) { unsubscribe(); } }; }, []);
更新关注关系的函数
async function updateFollow(db, follower, followee){ const followerRef = doc(db, "users", follower.uid); const followerSnap = await getDoc(followerRef); const followerData = followerSnap.data(); const followeeRef = doc(db, "users", followee.uid); if (followerData.following && followerData.following.includes(followee.profileName)){ await updateDoc(followerRef, { following: arrayRemove(followee.profileName) }) await updateDoc(followeeRef, { followers: arrayRemove(follower.profileName) }) } else{ await updateDoc(followerRef, { following: arrayUnion(followee.profileName) }) await updateDoc(followeeRef, { followers: arrayUnion(follower.profileName) }) } }
问题原因与解决方法
核心问题:订阅未正确清理
切换账号时,旧的onSnapshot订阅未及时取消,导致新、旧订阅同时触发,旧订阅的回调覆盖了新的用户状态。原代码的清理逻辑存在漏洞:onAuthStateChanged是异步触发的,账号切换时旧的订阅可能还未被清理,新订阅就已创建。
修复步骤
彻底清理所有订阅
修改useEffect逻辑,在每次触发onAuthStateChanged回调时,先取消旧的快照订阅,同时新增onAuthStateChanged自身的清理:useEffect(() => { let unsubscribeSnapshot; // 保存auth监听的取消函数 const unsubscribeAuth = onAuthStateChanged(auth, (user) => { // 先取消旧的快照订阅 if (unsubscribeSnapshot) { unsubscribeSnapshot(); } if (user) { const docRef = doc(db, "users", user.uid); unsubscribeSnapshot = onSnapshot(docRef, (doc) => { console.log(user.uid); console.log(doc.data().uid); setUserState(doc.data()); }); } else { setUserState(false); } }); // 组件卸载时同时清理auth监听和快照订阅 return () => { unsubscribeAuth(); if (unsubscribeSnapshot) { unsubscribeSnapshot(); } }; }, []);规避闭包陷阱
原代码中onSnapshot回调引用的user可能因闭包保留旧值,可直接使用auth.currentUser.uid创建文档引用,确保每次获取最新的用户ID:const docRef = doc(db, "users", auth.currentUser.uid);强制从服务器获取数据(可选)
若怀疑是Firestore缓存导致的问题,可在onSnapshot中指定优先从服务器拉取数据:unsubscribeSnapshot = onSnapshot(docRef, { source: 'server' }, (doc) => { setUserState(doc.data()); });校验更新函数参数
调用updateFollow时,确保传入的follower是当前登录用户的最新数据,避免因传入旧用户对象导致更新错误文档。
内容的提问来源于stack exchange,提问作者Anton
相关产品推荐
相关产品推荐

