我正在使用React路由v6构建嵌套路由.我面临两个问题:

  1. 如果单击具有子级的链接,url应该自动转到子级,但只呈现组件.URL仍然显示"/*".
  2. 在我的子元素身上,我有一个链接,可以让我了解整个路径.例如,它应该是"/routeC/subC3/newRoute"

请帮忙.

这是我的密码.

应用程序.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>
    </>
  );
}

This is a link to my sandbox.

推荐答案

这里有一个重构,它让您的大多数路由定义保持原样.变化主要在于渲染路由的方式和位置.

应用程序.js公司

删除routeValues个子项并将"/routeC/*"字符串文字更改为"/routeC",因为它用于路由路径and和链路.渲染时,将"*"通配符附加到路由的路径.

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分量图中,componentCChildrenRoute个分量,每个分量呈现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>
    </>
  );
}

Edit navigate-inside-a-child-route-not-working-properly-react-router-v6

Reactjs相关问答推荐

当我在React中使用类方法更新模型的状态时,它在严格模式下触发两次

全局上下文挂钩-替代不起作用

React onKeyUp不一致地使用快速Shift+键按压

在一个地方调用函数会影响其他地方调用该函数

客户端组件中服务器组件的两难境地

将动态元素中的输入数据传输到Reaction

有没有一种惯用的方式来接受特定的子元素?

有没有一种方法可以在没有强烈动画的情况下有条件地渲染组件?

同一文件中前端和后端的Nginx配置

状态更改是否卸载功能组件

在迭代状态时无法读取未定义的属性(读取 map )

如何测试使用 React.createportal 呈现的组件?

如何向 surveyjs 调查添加多个结尾?

刷新页面时状态改变问题

.filter() 函数在删除函数中创建循环 - React

将 dict 值转换并插入到react 钩子的列表中

Lodash 在命名导入中导入整个包

将鼠标悬停在仅适用于该类的第一个实例的 p5.js 类上

如何将本地视频文件上传到 Google Cloud

调用函数以获取数据并在数据到达时导航到链接