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;
问题原因
- API使用错误:React Router v6已经移除了v5版本的
exact属性,v6默认会对路由做精确匹配,只有加了/*后缀的路由才会前缀匹配子路径,代码中所有exact属性均为无效配置,会干扰嵌套路由解析。 - 路由语法冲突:index路由(父路由的默认子路由)不能配置
path属性,代码中Profile的默认子路由同时添加了index和path=":id",属于冲突配置,会导致路由匹配规则错乱。 - 架构设计缺陷:根据登录状态渲染两套完全独立的
<Routes>组件,会在登录状态变化时卸载重建整个路由树,导致路由上下文、导航状态丢失;如果useAuth存在异步获取本地token的逻辑,首次渲染和二次渲染的登录状态不一致,会触发路由反复切换,重定向逻辑混乱。 - 嵌套路由配置缺失:存在子路由的父级路由如果需要渲染子路由内容,必须配置
<Outlet/>作为子组件渲染出口,代码中/profile、/auth两个父路由均未配置出口,导致嵌套子路由无法正常命中渲染。
修复方案
不要拆分两套独立路由,统一维护一套路由配置,通过封装受保护路由组件做权限判断,修正错误的路由API使用:
- 封装两个权限路由组件,可直接放在路由文件中或抽为独立公共组件:
// 已登录才能访问的路由,未登录跳登录页 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; };
- 重写路由配置,移除所有无效的
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> ) }
- 修改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
相关产品推荐
相关产品推荐

