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

React Router按登录态配置路由时Navigate跳转异常问题

问题背景
  • 搭建了基于React Router v6的身份认证系统,需要根据用户登录状态匹配不同路由规则,展示对应可访问页面
  • 使用<Navigate/>组件实现重定向逻辑时出现异常:重定向规则未正确识别当前登录状态
  • 预期逻辑:
    • 已登录用户访问登录/注册页,自动重定向到首页(Main页)
    • 未登录用户访问个人主页(Profile页),自动重定向到登录页
  • 实际表现:无论登录状态如何,访问上述受限页面时都会被重定向到首页
问题代码

routes.jsx

import React from 'react';
import {
    Routes,
    Route,
    Navigate
  } from 'react-router-dom';
import Profile from './pages/Profile/Main/Profile';
import Login from './pages/Auth/Login/Login';
import Register from './pages/Auth/Register/Register';
import Main from './pages/Main/Main';
import { Loans } from './pages/Profile/Active/Loans';
import ErrorPage from './pages/errorPage/ErrorPage';

export const useRoutes = isAuthenticated => {
    if(isAuthenticated){
        return (
            <Routes>
                <Route path='/profile' exact>
                    <Route index path=":id" element={<Profile/>}/>
                    <Route path="loans" element={<Loans/>} exact/>
                </Route>
                <Route path='/' exact element={<Main/>}/>
                <Route
                    path="*"
                    element={<ErrorPage/>}
                />
                <Route
                    path="/auth/*"
                    element={<Navigate to="/" replace />}
                />
            </Routes>
        );
    } else {
        return (
            <Routes>
                <Route path='/auth' exact>
                    <Route path='login' element={<Login/>} exact />
                    <Route path="register" exact element={<Register/>}/>
                    <Route
                        path=""
                        element = {
                            <Navigate to="login" replace />
                        }
                    />
                </Route>
                <Route path='/' exact element={<Main/>}/>
                <Route
                        path="/profile/*"
                        element={<Navigate to="/auth/login" replace />}
                    />
                <Route
                    path="*"
                    element={<ErrorPage/>}
                />
            </Routes>
            )
    }
    
}

App.jsx

import {
  BrowserRouter
} from 'react-router-dom';
import {useRoutes} from './routes';
import 'materialize-css';
import { useAuth } from './hooks/auth.hook';
import { AuthContext } from './context/auth.context';


function App() {
  const {token, userId, login, logout} = useAuth();
  const isAuthenticated = !!token;
  const routes = useRoutes(isAuthenticated);
  return (
    <AuthContext.Provider value = {{
        token, login, logout, userId, isAuthenticated
      }}>
      <BrowserRouter>
        <div className="container">
          {routes}
        </div>
      </BrowserRouter>
    </AuthContext.Provider>
  );
}

export default App;
问题原因
  1. API使用错误:React Router v6已经移除了v5版本的exact属性,v6默认会对路由做精确匹配,只有加了/*后缀的路由才会前缀匹配子路径,代码中所有exact属性均为无效配置,会干扰嵌套路由解析。
  2. 路由语法冲突:index路由(父路由的默认子路由)不能配置path属性,代码中Profile的默认子路由同时添加了index和path=":id",属于冲突配置,会导致路由匹配规则错乱。
  3. 架构设计缺陷:根据登录状态渲染两套完全独立的<Routes>组件,会在登录状态变化时卸载重建整个路由树,导致路由上下文、导航状态丢失;如果useAuth存在异步获取本地token的逻辑,首次渲染和二次渲染的登录状态不一致,会触发路由反复切换,重定向逻辑混乱。
  4. 嵌套路由配置缺失:存在子路由的父级路由如果需要渲染子路由内容,必须配置<Outlet/>作为子组件渲染出口,代码中/profile、/auth两个父路由均未配置出口,导致嵌套子路由无法正常命中渲染。
修复方案

不要拆分两套独立路由,统一维护一套路由配置,通过封装受保护路由组件做权限判断,修正错误的路由API使用:

  1. 封装两个权限路由组件,可直接放在路由文件中或抽为独立公共组件:
// 已登录才能访问的路由,未登录跳登录页
const ProtectedRoute = ({ children }) => {
  const { isAuthenticated } = useContext(AuthContext);
  if (!isAuthenticated) {
    return <Navigate to="/auth/login" replace />;
  }
  return children;
};

// 已登录不能访问的路由(登录/注册页),已登录跳首页
const AuthRoute = ({ children }) => {
  const { isAuthenticated } = useContext(AuthContext);
  if (isAuthenticated) {
    return <Navigate to="/" replace />;
  }
  return children;
};
  1. 重写路由配置,移除所有无效的exact属性,给嵌套父路由添加<Outlet/>,修正冲突的index路由配置:
import React, { useContext } from 'react';
import {
    Routes,
    Route,
    Navigate,
    Outlet
} from 'react-router-dom';
import Profile from './pages/Profile/Main/Profile';
import Login from './pages/Auth/Login/Login';
import Register from './pages/Auth/Register/Register';
import Main from './pages/Main/Main';
import { Loans } from './pages/Profile/Active/Loans';
import ErrorPage from './pages/errorPage/ErrorPage';
import { AuthContext } from './context/auth.context';

export const useRoutes = () => {
  return (
    <Routes>
      {/* 首页公开访问 */}
      <Route path='/' element={<Main/>}/>

      {/* 个人主页相关路由,登录后可访问 */}
      <Route path='/profile' element={
        <ProtectedRoute>
          <Outlet/>
        </ProtectedRoute>
      }>
        <Route index element={<Navigate to="me" replace />}/>
        <Route path=":id" element={<Profile/>}/>
        <Route path="loans" element={<Loans/>}/>
      </Route>

      {/* 登录注册相关路由,未登录可访问 */}
      <Route path='/auth' element={
        <AuthRoute>
          <Outlet/>
        </AuthRoute>
      }>
        <Route path='login' element={<Login/>}/>
        <Route path="register" element={<Register/>}/>
        <Route index element={<Navigate to="login" replace />}/>
      </Route>

      {/* 404兜底页面 */}
      <Route path="*" element={<ErrorPage/>}/>
    </Routes>
  )
}
  1. 修改App.jsx中调用路由的逻辑,不需要传入登录状态参数,路由内部直接通过Context获取实时登录状态:
function App() {
  const {token, userId, login, logout} = useAuth();
  const isAuthenticated = !!token;
  const routes = useRoutes();
  return (
    <AuthContext.Provider value = {{
        token, login, logout, userId, isAuthenticated
      }}>
      <BrowserRouter>
        <div className="container">
          {routes}
        </div>
      </BrowserRouter>
    </AuthContext.Provider>
  );
}

额外检查项:需要确认useAuthhook中token的初始化和清除逻辑,确保登录成功时正确写入token,退出登录时彻底移除本地存储的token,避免登录状态判定错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:03:22