Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Recursive Friend routes in React-Router V6

This React-Router V5 recursive routes example shows exactly what I am trying to achieve: https://v5.reactrouter.com/web/example/recursive-paths

However I am using react-router-dom@6 and after converting my code to V6 the output is not what I would expect.

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);
}

When following the link to the next person id I get the console error "No routes matched location "/0/1" "

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

How can I render these routes recursively while still maintaining the same URL structure as in the V5 example, e.g. "host.com/1/3/2/..."?

>Solution :

The issue is that you are assuming that the root route is rendering nested routes (i.e. a Route rendering another Route directly) when actually you are rendering descendent routes (a routed component rendering another Routes and Route components). By rendering only one route and an outlet, you can’t go more than one level deep, e.g. you can render only the root level route, any paths more deep than this don’t have any route that matches, e.g. the invariant error you see.

The Routes component replaced the RRDv5 Switch component, so with understanding that in the RRDv5 recursive paths demo that each Person component is rendering descendent routes, the RRDv6 analog is for Person to render another Routes and recursive Route component. The other main difference between RRD v5 and v6 is that in order for descendent routes to be matchable and renderable their parent route necessarily needs to append the wildcard "*", or splat, matcher to the end of its path.

Example:

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>
  );
}

Edit recursive-friend-routes-in-react-router-v6

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading