React+Firebase使用useContext管理用户数据切换账号后数据不更新问题
问题根因
- useEffect依赖项配置错误。你两个实现版本中负责监听用户数据的useEffect都使用了空依赖数组,只会在Provider首次挂载时执行一次。后续
currentUser发生变化(切换账号、登出)时,不会重新触发获取新用户数据的逻辑。 - 没有清理Firestore实时监听。你调用
onSnapshot后没有返回取消监听的函数,前一个账号的实时监听会一直保留,旧数据更新时仍然会覆盖你当前的状态,导致数据错乱。 - 没有处理用户登出的空值场景。用户登出后
currentUser为null,直接读取user.uid会抛出运行时异常,导致后续逻辑中断。
修复方案
推荐直接整合逻辑到AuthContext,无需额外拆分DataContext,修复后的代码如下:
import React, { useContext, useState, useEffect } from 'react'; import { auth, storage, db } from '../firebase'; const AuthContext = React.createContext(); export function useAuth() { return useContext(AuthContext); } export function AuthProvider({ children }) { const [currentUser, setCurrentUser] = useState(); const [currentUserData, setCurrentUserData] = useState(); const [loading, setLoading] = useState(true); useEffect(() => { let unsubscribeUserDoc; // 保存用户文档监听的取消函数 const unsubscribeAuth = auth.onAuthStateChanged((user) => { setCurrentUser(user); // 先取消之前的用户文档监听 if (unsubscribeUserDoc) unsubscribeUserDoc(); if (user) { // 已登录,监听当前用户的文档 unsubscribeUserDoc = db.collection('users') .doc(user.uid) .onSnapshot((doc) => { setCurrentUserData(doc.data()); setLoading(false); }); } else { // 已登出,清空用户数据 setCurrentUserData(null); setLoading(false); } }); // 组件卸载时清理所有监听 return () => { unsubscribeAuth(); if (unsubscribeUserDoc) unsubscribeUserDoc(); } }, []); // 你的signup、login、logout实现 const signup = (email, password) => auth.createUserWithEmailAndPassword(email, password); const login = (email, password) => auth.signInWithEmailAndPassword(email, password); const logout = () => auth.signOut(); const value = { currentUser, currentUserData, signup, login, logout, } return ( <AuthContext.Provider value={value}> {!loading && children} </AuthContext.Provider> ); }
拆分DataContext的修复方案
如果你要保留拆分的DataContext,只需要修改DataProvider的useEffect逻辑,添加依赖项和清理逻辑即可:
useEffect(() => { // 处理用户未登录的情况 if (!currentUser) { setCurrentUserData(null); setLoading(false); return; } // 保存取消监听的函数 const unsubscribe = db.collection('users') .doc(currentUser.uid) .onSnapshot((doc) => { setCurrentUserData(doc.data()); setLoading(false); }); // 依赖变化/组件卸载时清理监听 return unsubscribe; }, [currentUser]); // 添加currentUser为依赖项,用户切换时自动重新执行
修改后无需改动App.js的Provider嵌套结构,即可正常跟随账号切换更新用户数据。
内容的提问来源于stack exchange,提问作者anulamatamang
相关产品推荐
相关产品推荐

