'Split Routes inside a single Switch into multiple components

I'm using React Router v5 and I ran into problems when trying to define routes split across multiple components. The case I tried is something like the following:

<Switch>
  <MyRoutes />
  <Route path="/foo">
    <Foo />
  </Route>
</Switch>

with the MyRoutes component looking like

<>
  <Route path="/bar">
    <Bar />
  </Route>
  <Route path="/baz">
    <Baz />
  </Route>
</>

The problem now is that routes declared after the custom MyRoutes component don't work, the custom component seems to match the route without rendering anything. The routes inside it do actually work as expected.

The reason I'm splitting the routes like this, apart from organizing related routes together is that I also need the separate routing component as a standalone to be able to integrate a set of components into a legacy web application. And I'd like to avoid duplicating the routes here for that purpose.

But obviously I'm doing something that you're not supposed to do with React Router, though I'm not entirely sure why this is an issue. So I would like to understand the limitation here a bit more to avoid running into variations of this again in the future. Why can't I split Routes like this into separate components within a single Switch, what are the exact limitations here?

Is putting a separate Switch into each component the right answer here? This does seem wrong from a conceptual point of view as each Route is supposed to be exclusive, only one of them should ever be rendered. Multiple Switch components would allow multiple components to be rendered at the same time, even though in practice this should not happen as the routes should be exclusive and not overlap.

What is the proper, intended way to have modular Routes in React Router v5 and not a single huge Routing component?



Solution 1:[1]

Issue

Routers inclusively render all matching routes whereas the Switch component exclusively renders the first match it finds. It's not strictly enforced but the only valid children of the Switch component are the Route and Redirect components. If you render any other component inside the Switch it will be returned and rendered and route matching completes, any routes after won't be reachable.

Switch

Renders the first child <Route> or <Redirect> that matches the location.

How is this different than just using a bunch of <Route>s?

<Switch> is unique in that it renders a route exclusively. In contrast, every <Route> that matches the location renders inclusively.

Solution

Render MyRoutes in a route on its own so the Switch component can manage path matching and rendering. I suggest using path="/" so the nested routes can also further be matched.

<Switch>
  <Route path="/foo">
    <Foo />
  </Route>
  <Route
    path="/" // <-- allows matching "/bar" and "/baz"
    component={MyRoutes}
  />
</Switch>

MyRoutes

You will also want to render these routes into a Switch component. Any time you want to exclusively match routes you'll use the Switch component.

<Switch>
  <Route path="/bar">
    <Bar />
  </Route>
  <Route path="/baz">
    <Baz />
  </Route>
</Switch>

Also keep in mind that within the Switch component that path order and specificity matters. You will want to order the routes in inverse order of path specificity. This is to attempt to match and render more specific paths first, then falling back to less specific paths.

Example:

<Switch>
  <Route path="/segment1/segment2/page" component={....} />
  <Route path="/segment1/page" component={....} />
  <Route path="/segment1" component={....} />
</Switch>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese