Recursive Paths

Sometimes you don't know all the possible routes for your application up front; for example, when building a filesystem browsing UI or determining URLs dynamically based on data. In these situations, it helps to have a dynamic router that can generate routes as needed at runtime.

This example lets you drill down into a friends list recursively, viewing each user's friend list along the way. As you drill down, notice each segment being added to the URL. You can copy/paste this link to someone else and they will see the same UI. Then click the back button and watch the last segment of the URL disappear along with the last friend list.


import React from "react";
import { BrowserRouter as Router, Routes, Route, Link, Navigate, useParams, useLocation } from "react-router";

export default function RecursiveExample() {
  return (
    <Router>
      <Routes>
        {/* The trailing /* means Person is free to match further segments itself */}
        <Route path="/:id/*" element={<Person />} />
        <Route path="/" element={<Navigate to="/0" replace />} />
      </Routes>
    </Router>
  );
}
function Person() {
  let { id } = useParams();
  let location = useLocation();
  let person = find(parseInt(id));
  return (
    <div>
      <h3>{person.name}&rsquo;s Friends</h3>
      <ul>
        {person.friends.map((friendId) => (
          <li key={friendId}>
            <Link to={`${location.pathname}/${friendId}`}>{find(friendId).name}</Link>
          </li>
        ))}
      </ul>
      {/* Person renders another Routes for the next segment, matching whatever
          is left of the URL after everything matched so far - this is what
          lets it recurse to an arbitrary depth without a fixed route config. */}
      <Routes>
        <Route path=":id/*" element={<Person />} />
      </Routes>
    </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) { return PEEPS.find((p) => p.id === id); }

Above, <Person> renders <Person> recursively.