React私有路由刷新重定向问题:Context API认证后如何正确渲染组件?
}; return ( <AuthFBContext.Provider value={contextValue}> {props.children} </AuthFBContext.Provider> );
};
export default AuthFBContext;
# 问题原因 1. **异步认证状态滞后**:页面刷新时,React组件重新挂载,`currentUser`初始值为空。Firebase的`onAuthStateChanged`是异步执行的,在它返回用户信息前,PrivateRoute已经完成渲染,此时`authFBCtx.currentUser`为空,触发重定向。 2. **useEffect依赖错误**:上下文提供者的`useEffect`依赖了`currentUser`,导致每次`currentUser`更新时重新订阅`onAuthStateChanged`,页面刷新时初始订阅执行后,`setCurrentUser`会触发`useEffect`再次执行,状态更新时机混乱。 3. **缺失加载状态判断**:没有在认证状态确认前做加载处理,直接判断`currentUser`是否存在,异步过程中误判用户未登录。 # 解决方案 ### 1. 修正上下文的useEffect订阅逻辑 将`useEffect`依赖改为空数组,确保仅在组件挂载时订阅一次,同时添加卸载时的取消订阅逻辑,新增加载状态标记: ```jsx // 上下文提供者内部 const [currentUser, setCurrentUser] = useState(null); const [isLoading, setIsLoading] = useState(true); // 新增加载状态 useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { setCurrentUser(user); dBCtx.getUserData1(user.uid) .then((result)=>{ if(result === false) { console.log('creating a user profile for' + user.uid) dBCtx.createUser(user.displayName, user.email, user.uid); } }) .catch(err => { console.log(err) }) .finally(() => setIsLoading(false)); // 结束加载 } else { setCurrentUser(null); setIsLoading(false); console.log('not logged in') } }); // 组件卸载时取消订阅,避免内存泄漏 return unsubscribe; }, [dBCtx]) // 仅依赖dBCtx,避免不必要的重渲染 // 更新上下文值,加入加载状态 const contextValue = { currentUser, isLoading, login, googleLogin, ... };
2. 修改PrivateRoute处理加载状态
在PrivateRoute中先判断加载状态,加载中时返回加载组件,避免误重定向:
export default function PrivateRoute({ component: Component, ...rest }) { const authFBCtx = useContext(AuthFBContext); const langCxt = useContext(LangContext); // 加载中时显示加载组件 if (authFBCtx.isLoading) { return <div>加载中...</div>; // 替换为项目中的加载组件 } return ( <Route {...rest} render={props => { return authFBCtx.currentUser ? <Component {...props} /> : <Redirect to={`/${langCxt.lang}/auth/signin`} /> }} ></Route> ); };
内容的提问来源于stack exchange,提问作者masafood
相关产品推荐
相关产品推荐

