[英]How to make tabs routing with React Router v6 with cross linking on nested page?
我正在嘗試使用頁面上的選項卡和交叉鏈接進行嵌套路由,但沒有成功。 請幫助使其工作。
我有一條路線/files
,其中包含兩個選項卡: Raw Medias tab
和Datasets tab
。 在選項卡切換頁面 url 沒有更改,它始終相同/files
。 如何在選項卡切換時更改頁面 url? 例如,頁面/files
上的默認選項卡是 Raw Medias。 那么如何實現:如果用戶登陸/files
頁面,則頁面 url 是/files/raw-medias
。 如果用戶打開Dataset tab
,則頁面 url 應該是/files/datasets
。
每個選項卡都有一個包含可點擊項目的列表。 在項目上單擊項目的頁面打開/files/raw-medias/id
。 此頁面有后退按鈕。 單擊后退按鈕打開/files
頁面,其中包含活動的默認選項卡。 如何在“后退”按鈕上單擊打開/files
頁面,其中包含該項目的活動選項卡? 例如,如果活動選項卡是Dataset tab
並且用戶單擊項目然后單擊返回按鈕,則Dataset tab
應該處於活動狀態。
原始媒體頁面有一個列表。 此列表是數據集選項卡(交叉鏈接)的內容。 如果用戶單擊該列表中的項目,那么他應該如何登陸數據集項目頁面? 例如,用戶在/files/raw-media/id
上並單擊列表中的項目,然后應打開/files/dataset/id
頁面。 目前我得到一個錯誤,因為這個 url 打開/files/raw-media/id/dataset/id
代碼沙盒 https ://codesandbox.io/s/react-router-tabs-ciivld?file=/src/App.tsx
我的路線:
const router = createBrowserRouter([
{
path: "/",
element: <HomePage />,
children: [
{
path: "/files",
element: <FilesPage />
},
{
path: "files/raw-media/:rawMediaId",
element: <RawMediaPage />
},
{
path: "files/dataset/:datasetId",
element: <DatasetPage />
}
]
}
]);
標簽頁
type Tab = "raw-medias" | "datasets";
const FilesPage = () => {
const [tab, setTab] = useState<Tab>("raw-medias");
const handleChangeTab = (tab: Tab) => {
setTab(tab);
};
return (
<Stack>
FilesPage
<Button onClick={() => handleChangeTab("raw-medias")}>
Raw Medias Tab
</Button>
<Button onClick={() => handleChangeTab("datasets")}>
Datasets Tab
</Button>
{tab === "raw-medias" ? <RawMediaList data={RAW_DATA} /> : null}
{tab === "datasets" ? <DatasetList data={DATASET_DATA} /> : null}
</Stack>
);
};
RawMediaPage.tsx(帶后退按鈕的單項頁面)
const RawMediaPage = () => {
const { rawMediaId } = useParams();
const navigate = useNavigate();
return (
<Stack>
<Typography>
This is RAW Media Page
</Typography>
<Button onClick={() => navigate(-1)}>
Go Back to tab list
</Button>
<Stack>
This is Dataset List on RAW Media Page
<DatasetList data={DATASET_DATA} />
</Stack>
</Stack>
);
};
DatasetList.tsx(包含可點擊項目的列表)
const navigate = useNavigate();
const handleClick = (id: number) => {
navigate(`dataset/${id}`);
};
return (
<Stack>
{data.map((item) => {
return (
<Box onClick={() => handleClick(item.id)} key={item.id}>
{item.name}
</Box>
);
})}
</Stack>
);
};
配置FilesPage
組件以將當前匹配的路由與“選項卡”耦合。 我們在這里使用NavLink
組件在選項卡之間導航,並通過使用NavLink
的isActive
children 屬性免費獲得“選項卡匹配”。
import { Stack, Typography, Button } from "@mui/material";
import { NavLink, Outlet } from "react-router-dom";
const FilesPage = () => {
return (
<Stack gap={"30px"}>
<Typography variant="h4" align={"center"}>
FilesPage
</Typography>
<Stack direction={"row"} gap={"10px"}>
<NavLink className="tab-link" to="raw-medias">
{({ isActive }: { isActive: boolean }) => (
<Button
variant="contained"
sx={{ background: isActive ? undefined : "gray" }}
>
Raw Medias Tab
</Button>
)}
</NavLink>
<NavLink className="tab-link" to="datasets">
{({ isActive }: { isActive: boolean }) => (
<Button
variant="contained"
sx={{ background: isActive ? undefined : "gray" }}
>
Datasets Tab
</Button>
)}
</NavLink>
</Stack>
<Stack>
<Outlet />
</Stack>
</Stack>
);
};
export default FilesPage;
css
.tab-link {
text-decoration: none;
}
配置路由,以便FilePages
將嵌套路由呈現為布局路由。
import "./styles.css";
import {
createBrowserRouter,
RouterProvider,
Navigate
} from "react-router-dom";
import { Box } from "@mui/material";
import HomePage from "./HomePage";
import FilesPage from "./FilesPage";
import RawMediaList from "./RawMediaList";
import DatasetList from "./DatasetList";
import RawMediaPage from "./RawMediaPage";
import DatasetPage from "./DatasetPage";
import { RAW_DATA, DATASET_DATA } from "./mockData";
const router = createBrowserRouter([
{
path: "/",
element: <HomePage />,
children: [
{
path: "/files",
element: <FilesPage />,
children: [
{
path: "raw-medias",
element: <RawMediaList data={RAW_DATA} />
},
{
path: "raw-medias/:rawMediaId",
element: <RawMediaPage />
},
{
path: "datasets",
element: <DatasetList data={DATASET_DATA} />
},
{
path: "datasets/:datasetId",
element: <DatasetPage />
},
{
index: true,
element: <Navigate to="./raw-medias" replace />
}
]
}
]
}
]);
export default function App() {
return (
<Box>
<RouterProvider router={router} />
</Box>
);
}
這些組件需要呈現指向特定詳細信息頁面的鏈接。
import { Box, Stack } from "@mui/material";
import { Link } from "react-router-dom";
const RawMediaList = ({ data }: { data: { id: number; name: string }[] }) => {
return (
<Stack gap={"10px"}>
{data.map((item) => {
return (
<Box
key={item.id}
component={Link}
to={`${item.id}`}
sx={{
color: "black",
padding: "10px 20px",
background: "lightgray",
textDecoration: "none"
}}
>
{item.name}
</Box>
);
})}
</Stack>
);
};
export default RawMediaList;
import { Box, Stack } from "@mui/material";
import { Link } from "react-router-dom";
const DatasetList = ({ data }: { data: { id: number; name: string }[] }) => {
return (
<Stack gap={"10px"}>
{data.map((item) => {
return (
<Box
key={item.id}
component={Link}
to={`/files/datasets/${item.id}`} // <-- absolute path
sx={{
color: "black",
padding: "10px 20px",
background: "lightgreen",
textDecoration: "none"
}}
>
{item.name}
</Box>
);
})}
</Stack>
);
};
export default DatasetList;
請注意, DatasetList
使用絕對路徑,因為它由兩個選項卡呈現,因此它不能從一個選項卡相對鏈接到另一個選項卡。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.