react-router-dom v6 登录状态路由重定向问题排查与实现
React Router v6 路由权限控制实现方案
适用场景
项目采用ReactJS搭配Laravel API开发,需要实现两类路由访问限制:
- 已登录用户访问
/login、/register等游客专属页面时,自动重定向到首页 - 未登录用户访问首页等受保护路由时,自动重定向到登录页
报错原因拆解
- 首次编写代码抛出
Uncaught Error: [Navigate] is not a <Route> component错误,核心原因是react-router-dom v6对路由结构有强制约束:<Routes>组件的直接子元素只能是<Route>组件。第一次的写法直接在<Route path="/login">的标签子节点里放了<Navigate>组件,违反了结构要求;同时代码还存在两个低级问题:重复声明了两个path="/login"的父路由、把注册页路由嵌套在/login父路由下,就算不抛错,注册页实际访问路径也会变成/login/register,和预期的/register完全不符。 - 第二次修改后未登录访问受保护路由不跳转,原因非常直接:只给
/login路由加了「已登录跳首页」的判断,完全没给首页等受保护路由加「未登录跳登录页」的拦截逻辑,自然不会触发重定向。
正确实现步骤
不要在路由配置里零散写三元判断,封装两个可复用的路由守卫组件,既符合v6的路由结构要求,也方便后续维护。
1. 封装两类路由守卫
首先封装游客路由守卫(给登录、注册页使用):
// components/GuestRoute.jsx import { Navigate } from "react-router-dom"; export default function GuestRoute({ children }) { // 读取本地存储的登录令牌判断登录状态 const isLoggedIn = !!localStorage.getItem("auth_token"); // 已登录直接替换路由跳转到首页,未登录则正常渲染子页面 return isLoggedIn ? <Navigate to="/" replace /> : children; }
再封装受保护路由守卫(给需要登录才能访问的业务页面使用):
// components/ProtectedRoute.jsx import { Navigate } from "react-router-dom"; export default function ProtectedRoute({ children }) { const isLoggedIn = !!localStorage.getItem("auth_token"); // 未登录直接替换路由跳转到登录页,已登录则正常渲染子页面 return isLoggedIn ? children : <Navigate to="/login" replace />; }
注意:
<Navigate>组件一定要加replace属性,替换当前路由历史记录,避免用户点击浏览器返回键时重复进入重定向循环。
2. 按规范配置路由
所有路由判断逻辑都放在<Route>的element属性内,严格遵守v6的路由结构要求:
// router/index.jsx import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; import Login from "../pages/Login"; import Register from "../pages/Register"; import Main from "../pages/Main"; import GuestRoute from "../components/GuestRoute"; import ProtectedRoute from "../components/ProtectedRoute"; export default function AppRouter() { return ( <Router> <Routes> {/* 受保护路由:登录后才可访问 */} <Route path="/" element={ <ProtectedRoute> <Main /> </ProtectedRoute> } /> {/* 游客路由:仅未登录时可访问 */} <Route path="/login" element={ <GuestRoute> <Login /> </GuestRoute> } /> <Route path="/register" element={ <GuestRoute> <Register /> </GuestRoute> } /> </Routes> </Router> ); }
补充说明
如果后续把登录状态存到Context、Redux等响应式状态容器里,只需要修改两个守卫组件里的登录状态读取逻辑即可,路由配置不需要做任何改动;不要直接在<Routes>或者<Route>的子节点位置放除了<Route>之外的其他组件,否则会持续触发路由结构类报错。
内容的提问来源于stack exchange,提问作者motionless570
相关产品推荐
相关产品推荐

