React页面刷新时useAuth状态瞬时变更导致路由跳转异常如何解决?
问题根源
你遇到的是React客户端渲染常见的初始化状态时序问题:
useAuthHook 的初始状态token = null、admin = false是硬编码的- 读取 localStorage 恢复登录态的逻辑在
useEffect中,而 useEffect 会在组件第一次渲染完成后才执行 - 第一次渲染时
isAuthenticated = false,useRoutes会生成未登录状态的路由配置,直接触发重定向到首页,等到 useEffect 更新登录态时,页面已经跳转完成了
解决方案:添加加载状态拦截
第一步:修改 Auth.hook.js,新增加载状态
const storageName = 'userData' export const useAuth = () => { const [token, setToken] = useState(null) const [admin, setAdmin] = useState(false) // 新增加载状态,初始为true,代表正在从本地存储恢复登录态 const [loading, setLoading] = useState(true) const login = useCallback((jwtToken, isAdmin) => { setToken(jwtToken) setAdmin(isAdmin) localStorage.setItem(storageName, JSON.stringify({ token: jwtToken, isAdmin: isAdmin, })) }, []) const logout = useCallback(() => { setToken(null) setAdmin(false) localStorage.removeItem(storageName) }, []) useEffect(() => { const data = JSON.parse(localStorage.getItem(storageName)) if (data && data.token) { login(data.token, data.isAdmin) } // 无论是否有登录态,读取完成后关闭加载状态 setLoading(false) }, [login]) // 将loading返回给调用方 return { login, logout, token, admin, loading } }
第二步:修改 App.js,加载完成前不渲染路由
function App() { const { token, login, logout, admin, loading } = useAuth() const isAuthenticated = !!token const routes = useRoutes(isAuthenticated, admin) // 登录态恢复中,渲染加载占位,避免生成错误路由 if (loading) { return <div className="loading">加载中...</div> } return ( <AuthContext.Provider value={{ token, login, logout, isAuthenticated, admin }}> <Router> <div className="app-container"> {routes} </div> </Router> </AuthContext.Provider> ); }
可选优化(仅纯客户端SPA可用)
如果不想显示加载占位,也可以直接在状态初始化时同步读取localStorage,省去等待useEffect执行的过程:
// Auth.hook.js 中修改状态初始化逻辑 const [token, setToken] = useState(() => { const data = JSON.parse(localStorage.getItem(storageName)) return data?.token ?? null }) const [admin, setAdmin] = useState(() => { const data = JSON.parse(localStorage.getItem(storageName)) return data?.isAdmin ?? false })
注意:该写法不支持服务端渲染(SSR/SSG)场景,服务端不存在localStorage对象,会导致报错。
内容的提问来源于stack exchange,提问作者n33t
相关产品推荐
相关产品推荐

