3

I'm having issues configuring react-router-dom with nested routes loaded by sub-modules. In my application I need to dynamically load modules that have their own nested routes. One of the requirement is to have the modules completely independent from the parent application. The loaded modules use relative routes to define their own navigation. The problem is that the relative navigation continue to append URL segments. I'm obviously missing something but I cannot figure it out.

The current behavior, that I would not expect, is that clicking multiple times to one of the nested navigation links will continue to append to the URL. Initially, after clicking to Nested the URL is mydomain.com/nested. If I click the link for sub the ULR changes to mydomain.com/nested/sub. If I click again sub it becomes mydomain.com/nested/sub/sub or mydomain.com/nested/sub/other if I click to the other link.

I would expect the URL to remain mydomain.com/nested/sub or change to mydomain.com/nested/other.

I made a Codesandbox that shows the issue.


export default function App() {
  return (
    <BrowserRouter>
      <div className='App'>
        <h1>React Router Nested Routes</h1>
      </div>

      <Routes>
        <Route element={<OuterLayout />}>
          <Route
            element={<Home />}
            index
            path='home'
          />
          <Route
            element={<Nested />}
            path='nested/*'
          />
          <Route
            element={<Unknown />}
            path='*'
          />
        </Route>
      </Routes>
    </BrowserRouter>
  )
}

function OuterLayout() {
  return (
    <div>
      <ul>
        <li>
          <Link to='/home'>Home</Link>
        </li>
        <li>
          <Link to='/nested'>Nested</Link>
        </li>
      </ul>

      <Outlet />
    </div>
  )
}

function Home() {
  return <section>Home</section>
}

function Unknown() {
  return <section>Unknown</section>
}

function Nested() {
  return (
    <Routes>
      <Route element={<NestedLayout />}>
        <Route
          element={<Sub />}
          index
        />
        <Route
          element={<Sub />}
          path='sub'
        />
        <Route
          element={<Other />}
          path='other'
        />
      </Route>
    </Routes>
  )
}

function NestedLayout() {
  return (
    <div>
      <ul>
        <li>
          <Link to='sub'>Sub</Link>
        </li>
        <li>
          <Link to='other'>Other</Link>
        </li>
      </ul>

      <Outlet />
    </div>
  )
}

function Sub() {
  return <section>Sub</section>
}

function Other() {
  return <section>Other</section>
}

0

1 Answer 1

1

React-Router v7 effectively changed how splat routes are matched, and navigated relative to/fom, especially regarding descendent routes.

  • Update the "/nested/*" route by splitting it into two routes, one nested in the other; a parent Route with the "/nested" path segment, and a nested child Route as an index route and path="*" to allow matching descendent routes.
  • Update NestedLayout to prepend extra ".." relative path segments to the link paths.

This allows links rendered in Nested's NestedLayout layout route component to navigate relative to Nested's sub-route instead, i.e. from "/*" instead of "../nested/*". These changes are briefly covered in the v6-to-v7 migration guide (see the "Update your Code" and "Update relative links" sections, specifically).

Old:

<Route path="nested/*" element={<Nested />} />
<Link to="sub">Sub</Link>
<Link to="other">Other</Link>

New:

<Route path="nested">
  <Route index path="*" element={<Nested />} />
</Route>
<Link to="../sub">Sub</Link>
<Link to="../other">Other</Link>

Full Code:

export default function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <h1>React Router Nested Routes</h1>
      </div>

      <Routes>
        <Route element={<OuterLayout />}>
          <Route element={<Home />} index path="home" />
          <Route path="nested">
            <Route element={<Nested />} index path="*" />
          </Route>
          <Route element={<Unknown />} path="*" />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}
function NestedLayout() {
  return (
    <div>
      <ul>
        <li>
          <Link to="../sub">Sub</Link>
        </li>
        <li>
          <Link to="../other">Other</Link>
        </li>
      </ul>

      <Outlet />
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.