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

React路由鉴权报错:Maximum update depth exceeded问题修复求助

问题描述

需要在app.js中实现以下路由鉴权逻辑:

  • 先检查用户是否已登录:已登录则跳转目标URL;未登录则自动跳转到/connexion登录页
  • 用户已登录时,进一步检查profile完善状态:状态为finished则跳转目标URL;否则跳转到/information资料完善页

原本仅做登录检查时功能正常,但添加资料完善检查后,出现Warning: Maximum update depth exceeded错误,推测是useEffect重复触发导致,但不知道具体修复方法,相关代码如下:

const App = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [tokenChecked, setTokenChecked] = useState(false);
  const { profile } = useStateContext();
  
  useEffect(() => {
    const token = sessionStorage.getItem("token");
    setIsLoggedIn(token ? true : false);
    setTokenChecked(true);
  }, []);

  return (
    <Router>
      {tokenChecked ? (
        <Routes>
          <Route element={<NavbarLayout />}>
            <Route path="/" exact element={<HomePage />} />
            <Route path="/about" exact element={<AboutPage />} />
            <Route path="/how-it-works" exact element={<HowItWorks />} />
          </Route>
          <Route element={<NoNavbarLayout />}>
            {/*<Route path="/register-type" exact element={<LoginPick />} />*/}
            <Route path="/connexion" exact element={<UserLogin />} />
            <Route path="/récupérer" exact element={<UserRecovery />} />
            <Route path="/register-user" exact element={<UserRegister />} />
            <Route
              path="/register-tech"
              exact
              element={<TechnicianRegister />}
            />
            <Route path="/register-admin" exact element={<AdminRegister />} />
          </Route>
          <Route element={<ConfirmLayout />}>
            <Route
              path="/confirmation"
              exact
              element={<AccountConfirmation />}
            />
            <Route path="/nonconnecte" exact element={<UserRedirectLMsg />} />
            <Route
              path="/validation/:id/:confirm"
              exact
              element={<AccountValidation />}
            />
          </Route>
          {isLoggedIn === true ? (
            <>
            {profile === 'finished' ? (
                <>
                  <Route element={<ConfirmLayout />}>
                    <Route path="/encours" exact element={<UserPending />} />
                    <Route
                      path="/information"
                      exact
                      element={
                        <Elements stripe={stripePromise}>
                          <UserInfo />
                        </Elements>
                      }
                    />
                  </Route>
                  <Route element={<DashboardLayout />}>
                    <Route
                      path="/nouvel-appareil"
                      exact
                      element={<UserNewDevice />}
                    />
                    <Route path="/new-project" exact element={<NewProject />} />
                    <Route
                      path="/demande-contrat"
                      exact
                      element={<NewContract />}
                    />
                    <Route path="/user-dash" exact element={<UserDash />} />
                    <Route path="/profile" exact element={<UserProfile />} />
                    <Route
                      path="/user-history"
                      exact
                      element={<UserHistory />}
                    />
                    <Route path="/navigation" exact element={<Compte />} />

                    <Route
                      path="/user-notification"
                      exact
                      element={<UserNotification />}
                    />
                    <Route
                      path="/user-projets-details/:id"
                      exact
                      element={<UserProjectDetails />}
                    />
                    <Route
                      path="/user-intervention-details/:id"
                      exact
                      element={<InterventionDetail />}
                    />
                    <Route
                      path="/user-details/:id"
                      exact
                      element={<UserDetail />}
                    />
                    <Route
                      path="/user-claim-details/:id"
                      exact
                      element={<UserClaimsDetail />}
                    />
                    <Route
                      path="/reclamations"
                      exact
                      element={<UserClaims />}
                    />
                    <Route path="/browse" exact element={<SearchGrid />} />

                    <Route
                      path="/technician-dash"
                      exact
                      element={<TechnicianDash />}
                    />
                    <Route
                      path="/technician-profile"
                      exact
                      element={<TechnicianProfile />}
                    />
                    <Route
                      path="/technician-projets"
                      exact
                      element={<TechnicianProjects />}
                    />
                    <Route
                      path="/technician-history"
                      exact
                      element={<UserHistory />}
                    />
                    <Route
                      path="/technician-projets-details/:id"
                      exact
                      element={<UserProjectDetails />}
                    />
                    <Route
                      path="/product/:id"
                      exact
                      element={<UserNewProductDetail />}
                    />
                    <Route
                      path="/admin-notification"
                      exact
                      element={<AdminNotification />}
                    />
                    <Route path="/new-user" exact element={<AddUser />} />
                    <Route path="/litiges" exact element={<Litige />} />
                    <Route
                      path="/réclamations"
                      exact
                      element={<Reclamation />}
                    />
                    <Route path="/users" exact element={<UsersList />} />
                  </Route>
                  <Route element={<NoNavbarLayout />}>
                    <Route
                      path="/register-type"
                      element={<Navigate to="/navigation" />}
                    />
                  </Route>
                </>
            ):(<>
              <Route
                path="*"
                element={<Navigate to="/information" replace />}
              />
          </>)}
            </>
          ) : isLoggedIn === false ? (
            <>
                <Route
                  path="*"
                  element={<Navigate to="/connexion" replace />}
                />
            </>
          ) : null}
        </Routes>
      ) : null}
    </Router>
  );
};

export default App;
错误原因

出现无限更新循环的核心原因不是useEffect重复触发,而是路由跳转的无限循环:
当用户profile未完善时,你用path="*"的路由规则匹配所有页面,然后跳转到/information;但/information本身也会被这个通配符路由匹配,导致再次触发跳转,形成无限循环,最终触发Maximum update depth exceeded警告。

另外,当前直接在Routes内部嵌套条件渲染路由的写法,会导致路由规则动态变化,也会加剧渲染不稳定的问题。

修复方案

改用路由守卫组件封装鉴权逻辑,将登录检查、profile完善检查的逻辑抽离成独立组件,避免直接在Routes中动态修改路由规则,同时排除/information页面被通配符路由匹配的情况。

步骤1:创建路由守卫组件

// 登录守卫:检查是否登录,未登录则跳转到登录页
const AuthGuard = ({ children }) => {
  const token = sessionStorage.getItem("token");
  const isLoggedIn = !!token;

  if (!isLoggedIn) {
    return <Navigate to="/connexion" replace />;
  }

  return children;
};

// Profile完善守卫:已登录但profile未完善时,跳转到资料完善页(排除/information本身)
const ProfileCompleteGuard = ({ children, location }) => {
  const { profile } = useStateContext();

  // 排除资料完善页本身,避免循环跳转
  if (profile !== 'finished' && location.pathname !== '/information') {
    return <Navigate to="/information" replace />;
  }

  return children;
};

步骤2:重构App组件的路由结构

将鉴权逻辑通过守卫组件包裹路由,不再在Routes内部做条件渲染:

const App = () => {
  const [tokenChecked, setTokenChecked] = useState(false);
  
  useEffect(() => {
    // 仅做token存在性检查的初始化,isLoggedIn直接通过token计算,无需存状态
    setTokenChecked(true);
  }, []);

  return (
    <Router>
      {tokenChecked ? (
        <Routes>
          {/* 无需鉴权的公共页面 */}
          <Route element={<NavbarLayout />}>
            <Route path="/" exact element={<HomePage />} />
            <Route path="/about" exact element={<AboutPage />} />
            <Route path="/how-it-works" exact element={<HowItWorks />} />
          </Route>
          <Route element={<NoNavbarLayout />}>
            <Route path="/connexion" exact element={<UserLogin />} />
            <Route path="/récupérer" exact element={<UserRecovery />} />
            <Route path="/register-user" exact element={<UserRegister />} />
            <Route path="/register-tech" exact element={<TechnicianRegister />} />
            <Route path="/register-admin" exact element={<AdminRegister />} />
          </Route>
          <Route element={<ConfirmLayout />}>
            <Route path="/confirmation" exact element={<AccountConfirmation />} />
            <Route path="/nonconnecte" exact element={<UserRedirectLMsg />} />
            <Route path="/validation/:id/:confirm" exact element={<AccountValidation />} />
          </Route>

          {/* 需要登录的路由:用AuthGuard包裹 */}
          <Route element={<AuthGuard />}>
            {/* 资料完善页:不需要profile检查(是完善入口) */}
            <Route element={<ConfirmLayout />}>
              <Route path="/information" exact element={
                <Elements stripe={stripePromise}>
                  <UserInfo />
                </Elements>
              } />
              <Route path="/encours" exact element={<UserPending />} />
            </Route>

            {/* 需要profile完善的路由:用ProfileCompleteGuard包裹 */}
            <Route element={<ProfileCompleteGuard />}>
              <Route element={<DashboardLayout />}>
                <Route path="/nouvel-appareil" exact element={<UserNewDevice />} />
                <Route path="/new-project" exact element={<NewProject />} />
                <Route path="/demande-contrat" exact element={<NewContract />} />
                <Route path="/user-dash" exact element={<UserDash />} />
                <Route path="/profile" exact element={<UserProfile />} />
                <Route path="/user-history" exact element={<UserHistory />} />
                <Route path="/navigation" exact element={<Compte />} />
                <Route path="/user-notification" exact element={<UserNotification />} />
                <Route path="/user-projets-details/:id" exact element={<UserProjectDetails />} />
                <Route path="/user-intervention-details/:id" exact element={<InterventionDetail />} />
                <Route path="/user-details/:id" exact element={<UserDetail />} />
                <Route path="/user-claim-details/:id" exact element={<UserClaimsDetail />} />
                <Route path="/reclamations" exact element={<UserClaims />} />
                <Route path="/browse" exact element={<SearchGrid />} />
                <Route path="/technician-dash" exact element={<TechnicianDash />} />
                <Route path="/technician-profile" exact element={<TechnicianProfile />} />
                <Route path="/technician-projets" exact element={<TechnicianProjects />} />
                <Route path="/technician-history" exact element={<UserHistory />} />
                <Route path="/technician-projets-details/:id" exact element={<UserProjectDetails />} />
                <Route path="/product/:id" exact element={<UserNewProductDetail />} />
                <Route path="/admin-notification" exact element={<AdminNotification />} />
                <Route path="/new-user" exact element={<AddUser />} />
                <Route path="/litiges" exact element={<Litige />} />
                <Route path="/réclamations" exact element={<Reclamation />} />
                <Route path="/users" exact element={<UsersList />} />
              </Route>
              <Route element={<NoNavbarLayout />}>
                <Route path="/register-type" element={<Navigate to="/navigation" replace />} />
              </Route>
            </Route>
          </Route>

          {/* 404或未匹配路由处理 */}
          <Route path="*" element={<Navigate to="/" replace />} />
        </Routes>
      ) : null}
    </Router>
  );
};

export default App;

额外优化点

  • 移除了isLoggedIn状态,直接通过sessionStorage.getItem("token")计算,避免状态不同步问题
  • 将鉴权逻辑抽离到守卫组件,代码结构更清晰,复用性更强
  • 明确区分了无需鉴权、仅需登录、需登录且profile完善的路由层级,避免路由规则冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:12:07