React Router v6嵌套子路由内部导航跳转异常问题
问题根因
两个异常均为React Router v6嵌套路由用法不符合规范导致,具体错误点:
- 路由配置错误:父路由的
/*通配符是路由匹配规则用的,不能直接写在导航链接的目标路径里,你直接把带/*的路径传给Link,导致跳转时URL残留通配符 - 子路由路径重复拼接:父路由加了
/*后,嵌套子路由只需要写相对路径即可,你手动全量拼接父路径,导致路径匹配逻辑混乱,重定向规则失效 - 父子组件渲染逻辑错误:父组件
ComponentC没有用<Outlet />渲染子路由,而是手动渲染所有Tab对应的组件,导致UI和路由状态脱节,URL无法同步更新 - 冗余的路径拼接逻辑:嵌套路由下不需要手动调用
useMatch拼接全路径,v6原生支持相对路径自动补全,手动拼接反而会出现路径错误、通配符残留问题 - 重定向规则重复定义:你把父路由的默认重定向写在子路由循环里,导致匹配优先级异常,访问父路径时无法正确触发跳转
修复步骤
- 拆分路由配置:导航用的父路径不带
/*,仅在Route组件的path属性上拼接/*做匹配规则 - 子路由全部改用相对路径,不要重复拼接父路由前缀;父路由默认重定向用
index路由实现,只写一次 - 移除App根节点多余的
<Outlet />,<Outlet />仅放在需要渲染子路由的父组件内部 ComponentC组件删除本地存储Tab激活状态的state,激活状态直接从URL读取,组件内渲染<Outlet />承载子路由内容,不再手动渲染所有TabPanel- 深层嵌套路由(比如subC3下的newRoute)直接用相对路径定义和跳转,删除所有手动调用
useMatch/useLocation拼接路径的冗余代码
修正后代码
App.js
import "./styles.css"; import { Navigate, Route, Routes, BrowserRouter, Link, Outlet } from "react-router-dom"; import ComponentC from "./ComponentC"; const ComponentA = () => <p>Component A</p>; const ComponentB = () => <p>Component B</p>; const ComponentC1 = () => <p>I am in Component C1</p>; const ComponentC2 = () => <p>I am in Component C2</p>; const SubComponentC3 = () => <p>SubComponent C3</p>; export const ComponentC3 = () => { return ( <> <p>Component C3</p> <Link to="newRoute">Take me to a new route</Link> <Routes> <Route path="newRoute" element={<SubComponentC3 />} /> </Routes> </> ); }; export const componentCChildren = [ { label: "Component C - 1", code: "subC1", component: ComponentC1 }, { label: "Component C - 2", code: "subC2", component: ComponentC2 }, { label: "Component C - 3", code: "subC3", component: ComponentC3 } ]; export const routeValues = [ { label: "Component A", path: "/routeA", component: ComponentA, children: [] }, { label: "Component B", path: "/routeB", component: ComponentB, children: [] }, { label: "Component C", path: "/routeC", component: ComponentC, children: componentCChildren } ]; export default function App() { return ( <div className="App"> <BrowserRouter> {routeValues.map((item) => ( <Link key={item.path} to={item.path} style={{ paddingRight: "10px" }}> {item.label} </Link> ))} <Routes> {routeValues.map((route) => { if (route.children.length > 0) { return ( <Route key={route.path} path={`${route.path}/*`} element={<route.component />} > {/* 父路由默认重定向到首个子路由 */} <Route index element={<Navigate to={route.children[0].code} replace />} /> {route.children.map((r) => ( <Route key={r.code} path={r.code} element={<r.component />} /> ))} </Route> ); } return ( <Route key={route.path} path={route.path} element={<route.component />} /> ); })} <Route path="*" element={<Navigate to="/routeA" replace />} /> </Routes> </BrowserRouter> </div> ); }
ComponentC.js
import Tab from "@mui/material/Tab"; import Box from "@mui/material/Box"; import TabContext from "@mui/lab/TabContext"; import TabList from "@mui/lab/TabList"; import { useNavigate, Outlet, useLocation } from "react-router-dom"; import { componentCChildren } from "./App"; export default function ComponentC() { const navigate = useNavigate(); const location = useLocation(); // 从URL读取当前激活的Tab const pathSegments = location.pathname.split('/').filter(Boolean); const activeTab = pathSegments[1] || componentCChildren[0].code; const handleTabChange = (e, tabId) => { navigate(tabId, { replace: true }); }; return ( <> <p>Component C</p> <TabContext value={activeTab}> <Box sx={{ borderBottom: 1, borderColor: "divider" }}> <TabList onChange={handleTabChange} aria-label="lab API tabs example"> {componentCChildren.map((tab) => { return <Tab key={tab.code} value={tab.code} label={tab.label} />; })} </TabList> </Box> {/* 渲染匹配到的子路由内容 */} <Outlet /> </TabContext> </> ); }
修复后效果
- 点击Component C链接时,自动重定向到
/routeC/subC1,URL同步更新,无通配符残留 - ComponentC3内的链接点击后正确跳转到
/routeC/subC3/newRoute,路径自动拼接无异常 - Tab切换、路由跳转时URL和UI状态完全同步,不会出现内容渲染但地址不变的问题
内容的提问来源于stack exchange,提问作者arunmmanoharan
相关产品推荐
相关产品推荐

