React Route组件渲染报错:鉴权包装组件的修复方案
React Router v6 登录鉴权报错解决及正确实现
错误原因
React Router v6 对 <Routes> 的直接子组件有严格限制,仅允许 <Route> 或 <React.Fragment> 作为其子元素。你写的 <PrivateRoute> 是自定义组件,直接放在 <Routes> 下触发了这个报错。另外,旧版(v5)中通过自定义Route包装组件的写法在v6中不再适用,v6采用基于element的路由模型,鉴权逻辑需要嵌入到路由的element属性中。
正确实现步骤
1. 重构 PrivateRoute 为元素包装组件
把原来返回 <Route> 的 PrivateRoute 改成纯鉴权逻辑组件,仅负责校验用户状态,通过则渲染子元素,不通过则重定向到登录页:
import { Navigate } from 'react-router-dom'; import { FC, ReactNode } from 'react'; import { usePermission } from './your-permission-path'; // 替换为你的usePermission实际路径 interface PrivateRouteProps { children: ReactNode; } const PrivateRoute: FC<PrivateRouteProps> = ({ children }) => { const { userIsAuthenticated } = usePermission(); // 未认证则重定向,replace属性避免回退栈保留当前无效路由 if (!userIsAuthenticated()) { return <Navigate to="/login" replace />; } // 已认证则渲染受保护的页面内容 return <>{children}</>; }; export default PrivateRoute;
2. 调整路由服务代码
在 <Routes> 中直接使用官方 <Route> 组件,私有路由的element用 PrivateRoute 包裹需要保护的页面内容,公开路由直接渲染即可:
import { Router, Routes, Route, Navigate } from 'react-router-dom'; import { FC } from 'react'; import { SecurityProvider } from './your-security-provider-path'; // 替换为实际路径 import PrivateRoute from './PrivateRoute'; import { privateRoutes, publicRoutes } from './your-routes-config-path'; // 替换为实际路径 import Layout from './Layout'; import BaseLayout from './BaseLayout'; export const RouterService: FC = () => { return ( <Router> <SecurityProvider> <Routes> {/* 渲染私有路由 */} {privateRoutes.map((route, index) => ( <Route key={index} path={route.path} element={ <PrivateRoute> <Layout> <route.element /> </Layout> </PrivateRoute> } /> ))} {/* 渲染公开路由 */} {publicRoutes.map((route, index) => ( <Route key={index} path={route.path} element={ <BaseLayout> <route.element /> </BaseLayout> } /> ))} {/* 匹配所有未定义路由,重定向到登录页 */} <Route path="*" element={<Navigate to="/login" replace />} /> </Routes> </SecurityProvider> </Router> ); };
3. 可选:扩展细粒度权限校验
如果需要基于权限的访问控制,可以给 PrivateRoute 添加权限校验逻辑:
// 扩展后的PrivateRoute interface PrivateRouteProps { children: ReactNode; requiredPermission?: string; } const PrivateRoute: FC<PrivateRouteProps> = ({ children, requiredPermission }) => { const { userIsAuthenticated, hasPermission } = usePermission(); if (!userIsAuthenticated()) { return <Navigate to="/login" replace />; } // 校验指定权限,无权限则重定向到403页面 if (requiredPermission && !hasPermission(requiredPermission)) { return <Navigate to="/403" replace />; } return <>{children}</>; };
使用时只需传入权限参数:
<Route path="/users" element={ <PrivateRoute requiredPermission="user:view"> <Layout> <UsersPage /> </Layout> </PrivateRoute> } />
内容的提问来源于stack exchange,提问作者Sam Fisher
相关产品推荐
相关产品推荐

