如何让React Hook实时反映用户登录状态?
解决React Hooks登录状态实时更新问题
问题描述
通过localStorage中的JWT标识用户登录状态,首次加载页面时Hook能正常获取用户数据,但点击「登出」按钮后组件状态未更新,必须刷新页面才生效。
原自定义Hook代码
export const useUser = () => { const [token] = useToken(); const getPayloadFromToken = token => { const encodedPayload = token.split('.')[1]; return JSON.parse(atob(encodedPayload)) } const [user,setUser] = useState(() => { if(!token) return null; return getPayloadFromToken(token); }) useEffect(() => { if(!token) { setUser(null); } else { setUser(getPayloadFromToken(token)); } }, [token]); return user; } export const useToken = () => { const [token, setTokenInternal] = useState(() => { return localStorage.getItem('token'); }); const setToken = newToken => { localStorage.setItem('token',newToken); setTokenInternal(newToken); } return [token, setToken]; }
原导航栏组件代码
const NavigationBar = () => { const user = useUser(); const logOut = () => { localStorage.removeItem('token'); }; return( <> <div>{user ? 'logged in' : 'logged out'}</div> <button onClick={logout}>Log Out</button> </> ); }
问题原因
登出时直接操作localStorage.removeItem('token'),但没有更新useToken内部的token状态。useUser的useEffect依赖的是useToken返回的token状态值,状态未变化就不会触发重新计算用户信息,导致组件不更新。另外导航栏里还存在函数名拼写错误:定义的是logOut,但按钮onClick绑定的是logout。
修复方案
1. 优化useToken的setToken方法
处理传入null的情况,自动移除localStorage中的token:
export const useToken = () => { const [token, setTokenInternal] = useState(() => { return localStorage.getItem('token'); }); const setToken = newToken => { if (newToken) { localStorage.setItem('token', newToken); } else { localStorage.removeItem('token'); } setTokenInternal(newToken); } return [token, setToken]; }
2. 修改导航栏组件的登出逻辑
调用useToken提供的setToken方法,而不是直接操作localStorage,同时修正函数名拼写错误:
const NavigationBar = () => { const user = useUser(); const [, setToken] = useToken(); // 获取setToken方法 const logOut = () => { setToken(null); // 通过setToken更新状态 }; return( <> <div>{user ? 'logged in' : 'logged out'}</div> <button onClick={logOut}>Log Out</button> </> ); }
3. 可选:优化useUser的错误处理
为token解析增加异常捕获,避免无效token导致的报错:
export const useUser = () => { const [token] = useToken(); const getPayloadFromToken = (token) => { try { const encodedPayload = token.split('.')[1]; return JSON.parse(atob(encodedPayload)); } catch (err) { console.error('解析token失败:', err); return null; } } const [user, setUser] = useState(() => { if(!token) return null; return getPayloadFromToken(token); }) useEffect(() => { if(!token) { setUser(null); } else { setUser(getPayloadFromToken(token)); } }, [token]); return user; }
原理说明
通过useToken封装token的读写逻辑,确保每次修改token时都会更新React状态,触发依赖该状态的组件重新渲染。useUser监听token状态变化,自动同步用户信息,实现登录/登出时的实时状态更新。
内容的提问来源于stack exchange,提问作者Spencer Perkins
相关产品推荐
相关产品推荐

