簡體   English   中英

如何使用嵌套頁面上的交叉鏈接使用 React Router v6 進行選項卡路由?

[英]How to make tabs routing with React Router v6 with cross linking on nested page?

我正在嘗試使用頁面上的選項卡和交叉鏈接進行嵌套路由,但沒有成功。 請幫助使其工作。

  1. 我有一條路線/files ,其中包含兩個選項卡: Raw Medias tabDatasets tab 在選項卡切換頁面 url 沒有更改,它始終相同/files 如何在選項卡切換時更改頁面 url? 例如,頁面/files上的默認選項卡是 Raw Medias。 那么如何實現:如果用戶登陸/files頁面,則頁面 url 是/files/raw-medias 如果用戶打開Dataset tab ,則頁面 url 應該是/files/datasets

  2. 每個選項卡都有一個包含可點擊項目的列表。 在項目上單擊項目的頁面打開/files/raw-medias/id 此頁面有后退按鈕。 單擊后退按鈕打開/files頁面,其中包含活動的默認選項卡。 如何在“后退”按鈕上單擊打開/files頁面,其中包含該項目的活動選項卡? 例如,如果活動選項卡是Dataset tab並且用戶單擊項目然后單擊返回按鈕,則Dataset tab應該處於活動狀態。

  3. 原始媒體頁面有一個列表。 此列表是數據集選項卡(交叉鏈接)的內容。 如果用戶單擊該列表中的項目,那么他應該如何登陸數據集項目頁面? 例如,用戶在/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>
  );
};

文件頁面.tsx

配置FilesPage組件以將當前匹配的路由與“選項卡”耦合。 我們在這里使用NavLink組件在選項卡之間導航,通過使用NavLinkisActive 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;
}

應用程序.tsx

配置路由,以便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使用絕對路徑,因為它由兩個選項卡呈現,因此它不能從一個選項卡相對鏈接到另一個選項卡。

演示

編輯 how-to-make-tabs-routing-with-react-router-v6-with-cross-linking-on-nested-page

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM