React-Router-Dom v6受保护路由实现异常 未登录跳转登录页方案咨询
问题排查
你的代码是React Router v5的写法,直接套用到v6版本自然无法运行,核心问题如下:
Route组件的render、component属性在v6版本已完全废弃,统一使用element属性传入JSX内容Routes组件的直接子元素只能是官方Route组件,不能直接放你自定义的AuthenticatedRoute组件- v6默认开启路径精确匹配,
exact属性已经被移除,写了也不会生效 - 嵌套路由的父级路径需要加子路径匹配规则,子路由不需要写父级路径前缀,且父级组件需要渲染
Outlet作为子路由的挂载出口
可行实现方案
1. 重写受保护路由组件
改成v6官方推荐的守卫模式,通过Outlet嵌套挂载受保护的子路由:
import React from "react"; import { Navigate, Outlet } from "react-router-dom"; const AuthenticatedRoute = () => { const isAuthenticated = !!localStorage.getItem("token"); // 已登录渲染子路由,未登录直接跳转到登录页,replace用于清除历史记录避免后退回到鉴权失败页面 return isAuthenticated ? <Outlet /> : <Navigate to="/auth/login" replace />; }; export default React.memo(AuthenticatedRoute);
2. 调整路由配置
按照v6的规则修改Routes.js:
import React, { lazy } from "react"; import { Navigate, Route, Routes } from "react-router-dom"; import AuthenticatedRoute from "./Components/Routes/AuthenticatedRoute"; // 请补充你自己的组件导入路径 import DashboardLayout from "./xxx/DashboardLayout"; import Dashboard from "./xxx/Dashboard"; import AdminPropManagement from "./xxx/AdminPropManagement"; import NewProperty from "./xxx/NewProperty"; import LoginPage from "./xxx/LoginPage"; const AppRoutes = () => { return ( <Routes> {/* 公开路由直接放在外层,比如登录页 */} <Route path="/auth/login" element={<LoginPage />} /> {/* 所有需要鉴权的路由都放在守卫路由的嵌套层级下 */} <Route element={<AuthenticatedRoute />}> {/* 访问/admin直接重定向到仪表盘 */} <Route path="/admin" element={<Navigate to="/admin/dashboard" replace />} /> {/* 父级布局路由 */} <Route path="/admin" element={<DashboardLayout />}> {/* 子路由不需要写父级前缀 */} <Route path="dashboard" element={<Dashboard />} /> <Route path="property-management" element={<AdminPropManagement />} /> <Route path="new-property" element={<NewProperty />} /> </Route> </Route> </Routes> ); }; export default AppRoutes;
3. 给布局组件添加子路由挂载点
在DashboardLayout组件需要渲染子路由的位置加入Outlet组件,否则子路由内容不会显示:
// DashboardLayout.jsx 示例 import { Outlet } from "react-router-dom"; const DashboardLayout = () => { return ( <div className="dashboard-container"> {/* 你的侧边栏、顶部导航等公共布局内容 */} <div className="content-area"> {/* 子路由内容会渲染到这里 */} <Outlet /> </div> </div> ); };
如果有不需要嵌套的单个受保护路由,也可以用简单的高阶函数封装实现:
// 定义鉴权包装函数 const withAuth = (Component) => { return !!localStorage.getItem("token") ? Component : <Navigate to="/auth/login" replace /> } // 路由中直接使用 <Route path="/user/center" element={withAuth(<UserCenter />)} />
内容的提问来源于stack exchange,提问作者Alexdev
相关产品推荐
相关产品推荐

