'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.
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 |