React-Router-Dom v6升级报错:无法在Router内渲染另一个Router求助
报错原因
- React Router v6 对 Router 实例的校验严格度远高于 v5,全局只允许存在1个
<Router>(包括<BrowserRouter>、<HashRouter>等所有Router子类)实例,出现嵌套就会抛出该报错,常见触发场景有两个:- 你自定义的
HomeLayoutRoute、PrivateRoute组件内部额外包裹了一层<BrowserRouter>或<Router>,v5 版本对这类嵌套的兼容性更高不会报错,v6 直接拦截 - 项目入口文件(通常是
src/index.js)中已经用<BrowserRouter>包裹了<App />组件,你当前的 App.js 中又写了一层<BrowserRouter>,形成嵌套
- 你自定义的
解决方案
按顺序排查修改即可:
- 清理自定义路由组件内的Router标签
打开HomeLayoutRoute、PrivateRoute两个组件的源码,删除内部所有的<Router>/<BrowserRouter>外层包裹。v6 中自定义路由仅需实现权限校验、布局渲染的逻辑即可,不需要自带Router。
合规的PrivateRoute写法参考:
// components/routing/PrivateRoute.js 示例 import { Navigate } from "react-router-dom"; const PrivateRoute = ({ children }) => { const isLogin = /* 你的登录态判断逻辑 */ return isLogin ? children : <Navigate to="/login" replace /> } export default PrivateRoute
- 全局仅保留一个Router实例
检查入口文件index.js,如果已经有如下代码:
// index.js 示例 import { BrowserRouter } from 'react-router-dom' import App from './App' ReactDOM.createRoot(document.getElementById('root')).render( <BrowserRouter> <App /> </BrowserRouter> )
则直接删除 App.js 中包裹内容的 <BrowserRouter> 标签即可。如果入口没有包Router,就保留App.js里的这一层即可。
- 修正v6下自定义路由的使用写法
v6 中<Routes>标签的直接子元素只能是<Route>组件,你之前直接把HomeLayoutRoute、PrivateRoute作为Routes子元素的写法不符合规范,需要调整为自定义组件包裹element内容的形式:
修正后的App.js完整代码参考:
import { Routes, Route } from "react-router-dom"; //Layouts import HomeLayoutRoute from "./components/layouts/HomeLayout"; //components import Home from './components/Home'; // Routing import PrivateRoute from "./components/routing/PrivateRoute"; // Screens import PrivateScreen from "./components/loginscreens/PrivateScreen"; import LoginScreen from "./components/loginscreens/LoginScreen"; import RegisterScreen from "./components/loginscreens/RegisterScreen"; import ForgotPasswordScreen from "./components/loginscreens/ForgotPasswordScreen"; import ResetPasswordScreen from "./components/loginscreens/ResetPasswordScreen"; const App = () => { return ( <div className="app"> <Routes> <Route path="/" element={ <HomeLayoutRoute> <Home /> </HomeLayoutRoute> } /> <Route path="/private" element={ <PrivateRoute> <PrivateScreen/> </PrivateRoute> } /> <Route path="/login" element={<LoginScreen/>} /> <Route path="/register" element={<RegisterScreen/>} /> <Route path="/forgotpassword" element={<ForgotPasswordScreen/>}/> <Route path="/passwordreset/:resetToken" element={<ResetPasswordScreen/>}/> </Routes> </div> ); }; export default App;
注:原代码中两个path为
/的路由会产生匹配冲突,这里将私有路由的路径调整为/private,你可根据业务需求自行调整路径规则。
内容的提问来源于stack exchange,提问作者Nuwan Chamikara
相关产品推荐
相关产品推荐

