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

React Router v6中PersistLogin组件在首页未触发的问题排查

问题:访问首页时PersistLogin组件未触发的原因及解决办法

我想要实现一个PersistLogin组件,用于验证用户是否持有有效的refresh token,若有效则获取新的access token。但用户访问网站首页('/')时该组件未触发,请问原因是什么?

路由配置代码

const Routes = () => {
   const { user } = useAuth();

   return (
      <Router>
         <Route index element={<Home />} />
         <Route path='auth-form' element={<AuthForm />}>
            <Route path='register' element={<Register />} />
            <Route path='login' element={<Login />} />
         </Route>
         {/* PersistLogin组件所在路由 */}
         <Route element={<PersistLogin />}>
            {user && (
               <>
                  {user.isDev ? (
                     <>
                        {DEV_NAVIGATION.map((nav) => (
                           <Route key={nav.path} path={`${nav.path}`} element={nav.component} />
                        ))}
                     </>
                  ) : (
                     <>
                        {RECRUITER_NAVIGATION.map((nav) => (
                           <Route key={nav.path} path={`${nav.path}`} element={nav.component} />
                        ))}
                        <Route path='/*' element={<Navigate to='/' replace={true} />} />
                     </>
                  )}
               </>
            )}
         </Route>
         <Route path='/*' element={<Navigate to='/' replace={true} />} />
      </Router>
   );
};

PersistLogin.tsx代码

const PersistLogin = () => {
   const [isLoading, setIsLoading] = useState(true);
   const refresh = useRefreshToken();
   const { access_token } = useAuth();

   useEffect(() => {
      const verifyRefreshToken = async () => {
         try {
            await refresh();
         } catch (e) {
            console.log(e);
         } finally {
            setIsLoading(false);
         }
      };

      !access_token ? verifyRefreshToken() : setIsLoading(false);
   }, [access_token, refresh]);

   return <>{isLoading ? <p>...Is loading</p> : <Outlet />}</>;
};

export default PersistLogin;

原因分析

  1. 路由层级不包含首页:首页路由<Route index element={<Home />} />是Router的直接子路由,完全独立于PersistLogin组件所在的路由分支。React Router只会匹配渲染对应层级的路由,所以访问首页时根本不会进入PersistLogin的路由范围,自然不会触发组件逻辑。
  2. PersistLogin仅包裹用户登录后的路由:当前PersistLogin的路由下只渲染user存在时的导航路由,首页不在这个嵌套结构里,不管用户是否登录,访问首页都不会经过PersistLogin组件。

解决办法

方案一:将首页路由嵌套到PersistLogin下

把首页路由放到PersistLogin的路由内部,让访问首页时必走PersistLogin的验证逻辑。修改后的路由结构如下:

const Routes = () => {
   const { user } = useAuth();

   return (
      <Router>
         {/* 让PersistLogin作为全局布局路由,包裹所有需要验证的页面 */}
         <Route element={<PersistLogin />}>
            <Route index element={<Home />} />
            <Route path='auth-form' element={<AuthForm />}>
               <Route path='register' element={<Register />} />
               <Route path='login' element={<Login />} />
            </Route>
            {user && (
               <>
                  {user.isDev ? (
                     <>
                        {DEV_NAVIGATION.map((nav) => (
                           <Route key={nav.path} path={`${nav.path}`} element={nav.component} />
                        ))}
                     </>
                  ) : (
                     <>
                        {RECRUITER_NAVIGATION.map((nav) => (
                           <Route key={nav.path} path={`${nav.path}`} element={nav.component} />
                        ))}
                        <Route path='/*' element={<Navigate to='/' replace={true} />} />
                     </>
                  )}
               </>
            )}
            <Route path='/*' element={<Navigate to='/' replace={true} />} />
         </Route>
      </Router>
   );
};

方案二:全局挂载PersistLogin组件

如果首页不需要验证,但需要触发refresh token的校验逻辑,可以把PersistLogin组件直接放到Router外面或者App的根组件中,而非仅作为路由的element。比如:

function App() {
  return (
    <PersistLogin>
      <Router>
        {/* 原路由结构 */}
      </Router>
    </PersistLogin>
  );
}

这种方式需要调整PersistLogin组件,去掉<Outlet />,改为直接渲染子组件:

const PersistLogin = ({ children }: { children: React.ReactNode }) => {
   const [isLoading, setIsLoading] = useState(true);
   const refresh = useRefreshToken();
   const { access_token } = useAuth();

   useEffect(() => {
      const verifyRefreshToken = async () => {
         try {
            await refresh();
         } catch (e) {
            console.log(e);
         } finally {
            setIsLoading(false);
         }
      };

      !access_token ? verifyRefreshToken() : setIsLoading(false);
   }, [access_token, refresh]);

   return <>{isLoading ? <p>...Is loading</p> : children}</>;
};

内容的提问来源于stack exchange,提问作者Simon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:35:11