React+Firebase中onAuthStateChanged导致已卸载组件更新状态报错
问题原因
- Firebase 的
onAuthStateChanged是异步回调,AuthProvider 初始化时user默认值为null,直到回调触发才会更新为真实的登录状态 - 进入 PurchasesNSales 页面时,第一次渲染拿到的
user是初始的null,useEffect 会立刻触发跳转,路由直接卸载该组件 - 后续
onAuthStateChanged回调触发,AuthProvider 更新user状态,已经卸载的 PurchasesNSales 组件会收到 Context 更新通知,尝试重渲染,就会触发「在已卸载组件上执行状态更新」的报错
修复方案
步骤1:修改 AuthProvider,新增加载状态
给 AuthContext 增加加载状态标识,用来标记 Firebase 登录状态是否校验完成:
export const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); // 初始为true,代表登录状态还在校验中 const [authLoading, setAuthLoading] = useState(true); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, user => { setUser(user); // 回调触发代表校验完成,关闭加载状态 setAuthLoading(false); }); return () => { unsubscribe(); } }, []); return ( <AuthContext.Provider value={{ user, authLoading }}>{children}</AuthContext.Provider> ); };
步骤2:修改 PurchasesNSales 组件的校验逻辑
等登录状态校验完成后再判断是否需要跳转,加载期间可以渲染加载提示避免页面闪烁:
function PurchasesNSales() { const { user, authLoading } = useContext(AuthContext); const history = useNavigate(); useEffect(() => { // 仅在校验完成且用户未登录时触发跳转 if (!authLoading && !user) history("/", { replace: true }); }, [user, authLoading, history]); // 校验期间渲染加载状态 if (authLoading) return <p>登录状态校验中...</p> return( <p>Welcome {user?.displayName}</p> ); } export default PurchasesNSales;
可选轻量修复方案
如果不想调整 Context 结构,也可以在组件内增加挂载标记避免无效更新:
useEffect(() => { let isMounted = true; if (isMounted && !user) { history("/", { replace: true }); } return () => { isMounted = false; } }, [user, history])
该方案仅能消除报错,无法解决页面加载初期的内容闪烁问题,更推荐新增加载状态的修复方式。
内容的提问来源于stack exchange,提问作者BSantos
相关产品推荐
相关产品推荐

