React Router 6.4私有路由配置报错,咨询正确实现方式
React Router 6.4 正确实现私有路由的方法
问题场景
我使用React Router的createBrowserRouter新特性配置路由,代码如下:
const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<RootLayout />}> <Route index element={<Landing />} /> <Route path="login" element={<Login />} /> <Route path="signup" element={<SignUp />} /> <Route path="manager" element={<ManagerLayout />}> <Route index path="dashboard" element={<Dashboard />} /> <Route path="team" element={<TeamLayout />}> <Route path="personel" element={<Personel />} /> </Route> <Route path="profile" element={<Profile />} /> </Route> <Route path="*" element={<NotFound />} /> </Route> ) ) function App() { return ( <AuthProvider> <RouterProvider router={router} /> </AuthProvider> ); }
为了限制部分路由的访问权限,我创建了如下PrivateRoute组件:
import React from 'react'; import { Route, Navigate } from 'react-router-dom'; import { useAuth } from './globalContext'; function PrivateRoute({ element, ...rest }) { const { isLoggedIn } = useAuth(); return isLoggedIn ? ( <Route {...rest} element={element} /> ) : ( <Navigate to="/login" replace /> ); } export default PrivateRoute;
但运行时出现报错:
Uncaught Error: [PrivateRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
原因分析
React Router 6.4+ 采用了新的路由配置模式(createBrowserRouter/RouterProvider),不再支持自定义类似PrivateRoute的组件作为Route的子元素。路由配置结构要求严格,所有直接子元素必须是官方的<Route>或<React.Fragment>,自定义组件返回<Route>的方式不再适用。
正确实现方式
方法一:使用权限包裹组件(推荐)
创建一个用于包裹需要权限验证的路由元素的组件,通过控制是否渲染子元素来实现权限拦截:
import { Navigate, useLocation } from 'react-router-dom'; import { useAuth } from './globalContext'; function PrivateWrapper({ children }) { const { isLoggedIn } = useAuth(); const location = useLocation(); // 未登录时跳转到登录页,保存当前位置以便登录后返回 if (!isLoggedIn) { return <Navigate to="/login" state={{ from: location }} replace />; } return children; }
然后修改路由配置,将需要保护的路由的element用PrivateWrapper包裹:
const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<RootLayout />}> <Route index element={<Landing />} /> <Route path="login" element={<Login />} /> <Route path="signup" element={<SignUp />} /> {/* 用PrivateWrapper包裹需要保护的父路由,子路由会自动继承权限验证 */} <Route path="manager" element={<PrivateWrapper><ManagerLayout /></PrivateWrapper>}> <Route index path="dashboard" element={<Dashboard />} /> <Route path="team" element={<TeamLayout />}> <Route path="personel" element={<Personel />} /> </Route> <Route path="profile" element={<Profile />} /> </Route> <Route path="*" element={<NotFound />} /> </Route> ) );
这种方式符合React Router 6.4+的设计逻辑,将权限验证逻辑与路由配置解耦,同时可以灵活控制单个或多个路由的权限。
方法二:使用路由Loader进行权限验证
利用React Router 6.4新增的loader钩子,在路由加载前进行权限检查,若未登录则触发重定向:
import { redirect } from 'react-router-dom'; // 注意:loader函数中不能直接使用React Hooks,需改为直接访问全局状态或调用API验证 export const authLoader = () => { // 实际项目中建议调用后端API验证登录状态,而非仅依赖前端状态 const auth = JSON.parse(localStorage.getItem('auth')); const isLoggedIn = auth?.isLoggedIn; if (!isLoggedIn) { // 重定向到登录页并携带当前路径 throw redirect({ pathname: '/login', state: { from: window.location.pathname }, }); } return null; };
修改路由配置,给需要保护的路由添加loader:
const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<RootLayout />}> <Route index element={<Landing />} /> <Route path="login" element={<Login />} /> <Route path="signup" element={<SignUp />} /> {/* 添加authLoader进行权限验证 */} <Route path="manager" element={<ManagerLayout />} loader={authLoader} > <Route index path="dashboard" element={<Dashboard />} /> <Route path="team" element={<TeamLayout />}> <Route path="personel" element={<Personel />} /> </Route> <Route path="profile" element={<Profile />} /> </Route> <Route path="*" element={<NotFound />} /> </Route> ) );
该方法适合需要在路由加载前执行异步验证(如检查token有效性)的场景,通过抛出redirect实现自动跳转。
内容的提问来源于stack exchange,提问作者jchm
相关产品推荐
相关产品推荐

