[英]Navigate inside a child route not working properly - React Router v6
我正在使用 React Router v6 来构建嵌套路由。 我面临两个问题:
请帮忙。
这是我的代码。
应用程序.js
import "./styles.css";
import {
Navigate,
Route,
Routes,
useMatch,
useLocation,
BrowserRouter,
Link,
Outlet
} from "react-router-dom";
import ComponentC from "./ComponentC";
import { Fragment } from "react";
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 = () => {
const location = useLocation();
const match = useMatch(location.pathname);
return (
<>
<p>Component C3</p>
<Link to={`${match.path}/newRoute`}>Take me to a new route</Link>
<Routes>
<Route
exact
path={`${match.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.children.map((r, i, arr) => (
<Fragment key={r.code}>
<Route
path={`${route.path}/${r.code}`}
element={<r.component />}
/>
<Route
path={route.path}
element={<Navigate to={`${route.path}/${arr[0].code}`} />}
/>
</Fragment>
))}
</Route>
);
}
return (
<Route
key={route.path}
path={route.path}
element={<route.component />}
/>
);
})}
<Route path="*" element={<Navigate to="routeA" />} />
</Routes>
<Outlet />
</BrowserRouter>
</div>
);
}
组件C.js
import { useState } from "react";
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 TabPanel from "@mui/lab/TabPanel";
import { useNavigate, useMatch, useLocation } from "react-router-dom";
import { componentCChildren } from "./App";
export default function ComponentC(props) {
const navigate = useNavigate();
const location = useLocation();
const match = useMatch(location.pathname);
const [tabId, setTabId] = useState(componentCChildren[0].code);
const handleTabChange = (e, tabId) => {
console.log("tabId", tabId);
navigate(`${tabId}`);
setTabId(tabId);
};
return (
<>
<p>Component C</p>
<TabContext value={tabId}>
<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>
{componentCChildren.map((tab) => {
return (
<TabPanel key={tab.code} value={tab.code}>
{<tab.component />}
</TabPanel>
);
})}
</TabContext>
</>
);
}
这是我的沙盒的链接。
这是一个重构,它使您的大多数路由定义保持不变。 变化主要在于路线的呈现方式和位置。
应用程序.js
删除routeValues
子项并将"/routeC/*"
字符串文字更改为"/routeC"
,因为它同时用于路由路径和链接。 渲染时将"*"
通配符附加到路由的路径。
ComponentC3
将使用相对链接和路径到达".../newRoute"
,其中“...”是当前匹配的路由路径。
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 routeValues = [
{
label: "Component A",
path: "/routeA",
component: ComponentA,
},
{
label: "Component B",
path: "/routeB",
component: ComponentB,
},
{
label: "Component C",
path: "/routeC",
component: ComponentC,
}
];
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) => (
<Route
key={route.path}
path={`${route.path}/*`} // <-- append wildcard '*' here
element={<route.component />}
/>
))}
<Route path="*" element={<Navigate to="routeA" />} />
</Routes>
</BrowserRouter>
</div>
);
}
组件C.js
在这里,您可以将componentCChildren
渲染为后代路由。 在一个新的Routes
组件中,将componentCChildren
映射到Route
组件,每个组件都呈现一个TabPanel
组件。 再次将"*"
通配符匹配器附加到路由路径,以便可以匹配更多的后代路由。 使用useEffect
挂钩发出命令式重定向,从"/routeC"
到"/routeC/subC1"
的第一个选项卡。
export default function ComponentC(props) {
const navigate = useNavigate();
useEffect(() => {
if (componentCChildren?.[0]?.code) {
// redirect to first tab if it exists
navigate(componentCChildren[0].code, { replace: true });
}
// run only on component mount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const [tabId, setTabId] = useState(componentCChildren[0].code);
const handleTabChange = (e, tabId) => {
console.log("tabId", tabId);
navigate(tabId, { replace: true }); // just redirect between tabs
setTabId(tabId);
};
return (
<>
<p>Component C</p>
<TabContext value={tabId}>
<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>
<Routes>
{componentCChildren.map((tab) => {
const TabComponent = tab.component;
return (
<Route
key={tab.code}
path={`${tab.code}/*`} // <-- append wildcard '*' here
element={
<TabPanel value={tab.code}>
<TabComponent />
</TabPanel>
}
/>
);
})}
</Routes>
</TabContext>
</>
);
}
在ComponentC
中,您只需要传递<Outlet />
。 我更新了你的工作演示请在这里检查
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.