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

React Router Dom v6已认证用户仍被重定向至登录路由求助

问题根源

你的PrivateRoute会把已认证用户重定向到登录页,核心原因是组件初始化时的状态更新时机不匹配:

  • App组件挂载时,isAuth初始值是false,PrivateRoute会立刻触发重定向
  • 读取localStorage认证信息的useEffect是在组件挂载后才执行,等isAuth被更新为true时,重定向已经完成了

另外,你原来的useEffect依赖authState.isAuth,会导致每次isAuth变化都重复执行认证检查,完全没必要,还可能引发不必要的状态循环。

解决方案

1. 新增加载状态,避免过早重定向

在App的authState里加入isLoading状态,在认证状态未确定前,不触发重定向也不渲染受保护内容。

2. 修正useEffect依赖项

把useEffect的依赖改成空数组,确保只在组件挂载时执行一次认证检查。

修改后的代码

App.js关键部分修改

function App(props) {
  const navigate = useNavigate();
  // 新增isLoading状态,初始为true
  const [authState, setAuthState] = useState({
    isAuth: false,
    token: null,
    userId: null,
    isLoading: true,
  });
  const [showNav, setShowNav] = useState(true);

  // 依赖项改为空数组,只在组件挂载时执行一次
  useEffect(() => {
    if (window.location.href.includes("admin")) {
      setShowNav(false);
    }
    const token = localStorage.getItem("token");
    const expiryDate = localStorage.getItem("expiryDate");
    
    // 没有token或过期,直接设置加载完成
    if (!token || !expiryDate) {
      setAuthState(prev => ({
        ...prev,
        isLoading: false
      }));
      return;
    }

    const userId = localStorage.getItem("userId");
    const remainingMilliseconds = new Date(expiryDate).getTime() - new Date().getTime();
    
    // 检查token是否过期
    if (remainingMilliseconds <= 0) {
      logoutHandler();
      setAuthState(prev => ({...prev, isLoading: false}));
      return;
    }

    setAuthState((prevState) => {
      return {
        ...prevState,
        isAuth: true,
        token: token,
        userId: userId,
        isLoading: false, // 加载完成,更新状态
      };
    });
    setAutoLogout(remainingMilliseconds);
  }, []); // 移除authState.isAuth依赖

  // ... 其他函数保持不变

  return (
    <div className="App">
      {showNav && (
        <Nav
          token={authState.token}
          isAuth={authState.isAuth}
          onLogout={logoutHandler}
        />
      )}
      <Routes>
        {/* ... 其他路由保持不变 */}
        <Route
          path="/orders"
          element={
            <PrivateRoute {...authState}>
              <Orders token={authState.token} />
            </PrivateRoute>
          }
        />
        {/* ... 其他路由保持不变 */}
      </Routes>
    </div>
  );
}

PrivateRoute.js修改

const PrivateRoute = (props) => {
  // 加载状态时,渲染加载提示(可以换成你自己的加载组件)
  if (props.isLoading) {
    return <div>加载中...</div>;
  }

  if (!props.isAuth) {
    return <Navigate to="/login" replace />;
  }
  return props.children;
};

export default PrivateRoute;
额外注意事项
  • 登录成功后,不需要手动设置isLoading,因为初始挂载时的useEffect已经把它设为false了
  • 自动登出逻辑里,也要确保isLoading不会被错误设置
  • 加载提示可以换成更友好的UI组件,比如Spinner

内容的提问来源于stack exchange,提问作者Rohan Rana Magar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 02:15:33