React Router报错:ProtectedRoute非Route组件,无法作为Routes子元素
解决React Router v6中ProtectedRoute报错:
<ProtectedRoute /> is not a <Route> component 错误原因
- React Router v6 强制要求
<Routes>的直接子元素必须是<Route>或<React.Fragment>,自定义组件不能直接作为子节点(即便组件内部返回<Route>,也不符合v6的路由配置规范) - v6 移除了
<Route>的render属性,统一使用element属性传递要渲染的组件,你的代码中仍在使用render,这也是报错的核心诱因之一
修复方案
方案一:将ProtectedRoute重构为权限校验容器组件
这种方式更贴合v6的设计思路,把权限校验逻辑封装成容器,包裹需要保护的页面组件:
1. 修改ProtectedRoute组件
import { Navigate, useLocation } from 'react-router-dom'; const adminUsers = [ {username:'admin', password:'admin'} // 其他管理员用户 ]; const ProtectedRoute = ({ children }) => { const location = useLocation(); const currentUser = localStorage.getItem('user'); const isAdmin = adminUsers.some(user => user.username === currentUser); // 校验通过则渲染子组件,否则重定向到登录页 if (currentUser && isAdmin) { return children; } return <Navigate to="/login" replace state={{ from: location }} />; }; export default ProtectedRoute;
2. 修改App中的路由配置
在<Route>的element属性中用ProtectedRoute包裹需要保护的页面:
import { BrowserRouter, Route, Routes } from 'react-router-dom'; import Home from './pages/Home'; import Login from './pages/Login'; import Register from './pages/Register'; import BookingCar from './pages/BookingCar'; import AddCar from './pages/AddCar'; import Admin from './pages/Admin'; import EditCar from './pages/EditCar'; import ProtectedRoute from './components/ProtectedRoute'; import UserBookings from './pages/userBookings'; function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home />} /> <Route path="/login" element={<Login />} /> <Route path="/register" element={<Register />} /> {/* 受保护路由配置 */} <Route path="/booking/:carid" element={ <ProtectedRoute> <BookingCar /> </ProtectedRoute> } /> <Route path="/userbookings" element={ <ProtectedRoute> <UserBookings /> </ProtectedRoute> } /> <Route path="/addcar" element={ <ProtectedRoute> <AddCar /> </ProtectedRoute> } /> <Route path="/editcar/:carid" element={ <ProtectedRoute> <EditCar /> </ProtectedRoute> } /> <Route path="/admin" element={ <ProtectedRoute> <Admin /> </ProtectedRoute> } /> </Routes> </BrowserRouter> ); } export default App;
方案二:让ProtectedRoute返回标准的Route组件
如果你想保留类似原写法的结构,可以让ProtectedRoute接收路由参数,返回符合v6规范的Route组件:
1. 修改ProtectedRoute组件
import { Navigate, Route, useLocation } from 'react-router-dom'; const adminUsers = [ {username:'admin', password:'admin'} // 其他管理员用户 ]; const ProtectedRoute = ({ path, element }) => { const location = useLocation(); const currentUser = localStorage.getItem('user'); const isAdmin = adminUsers.some(user => user.username === currentUser); return ( <Route path={path} element={ currentUser && isAdmin ? element : <Navigate to="/login" replace state={{ from: location }} /> } /> ); }; export default ProtectedRoute;
2. App中的路由配置可保持不变
此时原App路由写法能正常工作,因为ProtectedRoute内部返回的是标准<Route>组件,符合v6对<Routes>子元素的要求。
额外注意事项
- 确保安装的是React Router v6版本,v5写法与v6差异较大
localStorage.getItem('user')获取的是字符串,要确保adminUsers中的username也是字符串类型,避免校验失败- 登录成功后,需正确将用户名存入
localStorage.setItem('user', 'admin'),否则权限校验会不通过
内容的提问来源于stack exchange,提问作者Hiwa Sedradin
相关产品推荐
相关产品推荐

