You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React页面刷新时useAuth状态瞬时变更导致路由跳转异常如何解决?

问题根源

你遇到的是React客户端渲染常见的初始化状态时序问题:

  • useAuth Hook 的初始状态 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 23:36:02