网站搜索

reactjs - React-Router V6 中的递归好友路由


这个 React-Router V5 递归路由示例正好展示了我想要实现的内容:https://v5.reactrouter.com/web/example/recursive-paths

然而,我正在使用 react-router-dom@6,并且在将我的代码转换为 V6 后,输出结果并不是我所期望的。

import {
  Routes,
  Route,
  Link,
  useParams,
  Outlet,
} from "react-router-dom";

export default function RecursiveExample() {
  return (
    <>
      <Routes>
        <Route path="/:id" element={<Person />} />
      </Routes>
    </>
  );
}

function Person() {
  let { id } = useParams();
  let person = find(parseInt(id as string, 10));

  return (
    <div>
      <h3>{person!.name}’s Friends</h3>

      <ul>
        {person!.friends.map(id => (
          <li key={id}>
            <Link to={`${id}`}>{find(id)?.name}</Link>
          </li>
        ))}
      </ul>

      {/* Outlet will render any nested routes */}
      <Outlet />
    </div>
  );
}

const PEEPS = [
  { id: 0, name: "Michelle", friends: [1, 2, 3] },
  { id: 1, name: "Sean", friends: [0, 3] },
  { id: 2, name: "Kim", friends: [0, 1, 3] },
  { id: 3, name: "David", friends: [1, 2] }
];

function find(id:any) {
  return PEEPS.find(p => p.id === id);
}

当点击链接到下一个人 id 时,我在控制台得到错误 "No routes matched location "/0/1" "

我如何在递归渲染这些路由的同时,仍然保持与 V5 示例中相同的 URL 结构,例如 "host.com/1/3/2/..."?

答案#1

问题在于,你假设根路由正在渲染嵌套路由(即一个Route直接渲染另一个Route),而实际上你渲染的是子孙路由(一个路由组件渲染另一个Routes和Route组件)。通过只渲染一个路由和一个出口,你无法深入超过一级,例如,你只能渲染根层路由,任何更深的路径都没有匹配的路由,例如你看到的不变量错误。

Routes 组件取代了 RRDv5 的 Switch 组件,因此了解到在 RRDv5 的递归路径演示中,每个 Person 组件都在渲染子路由,那么 RRDv6 的对应做法是让 Person 渲染另一个 Routes 和递归 Route 组件。RRD v5 和 v6 之间的另一个主要区别是,为了使子路由可匹配并可渲染,其父路由必须在路径末尾添加通配符 "*",或称 splat 匹配器。

示例:

export default function RecursiveExample() {
  return (
    <Routes>
      <Route index element={<Navigate to="/0" replace />} />
      <Route path="/:id/*" element={<Person />} />
    </Routes>
  );
}
function find(id?: string | number) {
  return PEEPS.find(p => String(p.id) === String(id));
}

function Person() {
  const { id } = useParams();
  const person = find(id);

  return (
    <div>
      <h3>{person!.name}’s Friends</h3>

      <ul>
        {person!.friends.map(id => (
          <li key={id}>
            <Link to={`${id}`}>{find(id)?.name}</Link>
          </li>
        ))}
      </ul>

      <Routes>
        <Route path="/:id/*" element={<Person />} />
      </Routes>
    </div>
  );
}