React路由报错:<Routes>子组件必须为<Route>,侧边栏需排除/login路由
报错原因分析
你遇到的[Routes] is not a <Route> component. All component children of <Routes> must be a <Route>错误,是因为React Router v6不允许在<Route>的子节点直接放置<Routes>,嵌套路由需要通过<Outlet>组件实现。同时你的代码混合了v5和v6的路由写法(比如旧版<Route>直接包裹内容而非使用element属性),导致逻辑混乱。
核心解决方案
- 统一React Router v6写法:所有路由必须包裹在
<Routes>内,使用element属性指定渲染组件,移除v5风格的<Route>写法。 - 修复嵌套路由结构:受保护路由(
ProtectedRoutes)内部通过<Outlet>渲染子路由,而非嵌套<Routes>。 - 条件渲染SideBar:通过
useLocation获取当前路径,仅当路径不是/login时渲染侧边栏。
修改后的代码示例
1. App.js 重构
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom'; import { useState } from 'react'; import SideBar from './SideBar'; import Login from './Login'; import ProtectedRoutes from './ProtectedRoutes'; import Main from './Main'; function App() { const [inactive, setInactive] = useState(false); const location = useLocation(); // 判断是否需要显示SideBar const showSideBar = location.pathname !== '/login'; return ( <Router> <div className="App"> {/* 条件渲染SideBar */} {showSideBar && ( <SideBar onCollapse={(inactive) => { console.log(inactive); setInactive(inactive); }} /> )} <div className={`container ${inactive ? "inactive" : ""}`}> <Routes> {/* 登录路由,不显示SideBar */} <Route path="/login" element={<Login />} /> {/* 受保护的路由组,需要验证权限 */} <Route path="/" element={<ProtectedRoutes />}> {/* 子路由通过Outlet渲染 */} <Route index element={<h1>Dashboard</h1>} /> <Route path="main" element={<Main />} /> <Route path="content" element={<h1>Content</h1>}> <Route path="courses" element={<h1>Courses</h1>} /> <Route path="videos" element={<h1>Videos</h1>} /> </Route> <Route path="design" element={<h1>Design</h1>} /> <Route path="content-2" element={<h1>Content 2</h1>}> <Route path="courses" element={<h1>Courses</h1>} /> <Route path="videos" element={<h1>Videos</h1>} /> </Route> <Route path="design-2" element={<h1>Design 2</h1>} /> <Route path="design-3" element={<h1>Design 3</h1>} /> <Route path="design-4" element={<h1>Design 4</h1>} /> </Route> </Routes> </div> </div> </Router> ); } export default App;
2. ProtectedRoutes.js 调整
import { Outlet, Navigate } from 'react-router-dom'; function ProtectedRoutes() { // 替换为你的实际权限验证逻辑,比如判断用户是否登录 const isAuthenticated = true; return isAuthenticated ? <Outlet /> : <Navigate to="/login" />; } export default ProtectedRoutes;
3. SideBar组件(补充说明)
你的menuItems可以直接在SideBar组件中生成导航菜单,无需在App.js中零散渲染路由:
import { Link } from 'react-router-dom'; import { menuItems } from './menuItems'; function SideBar({ onCollapse }) { return ( <div className="sidebar"> {/* 这里添加折叠按钮逻辑 */} {menuItems.map(menu => ( <div key={menu.name} className="menu-item"> <Link to={menu.to}>{menu.name}</Link> {/* 渲染子菜单 */} {menu.subMenus && menu.subMenus.length > 0 && ( <div className="submenu"> {menu.subMenus.map(subMenu => ( <Link key={subMenu.name} to={subMenu.to}>{subMenu.name}</Link> ))} </div> )} </div> ))} </div> ); } export default SideBar;
关键注意点
- React Router v6中
exact属性已被移除,路由默认是精准匹配,根路由用index属性指定默认子路由。 - 所有路由必须放在
<Routes>组件内部,不能直接在组件中零散渲染<Route>。 - 嵌套路由依赖
<Outlet>组件作为子路由的占位符,而非嵌套<Routes>。
内容的提问来源于stack exchange,提问作者Daniel L
相关产品推荐
相关产品推荐

