In the documentation for react-router v6 (https://reactrouter.com/en/main/route/route) it says
Omitting the path makes this route a "layout route". It participates in UI nesting, but it does not add any segments to the URL
So why doesn't this work?
const App = () =>
<Routes>
<Route path='/abc' element={<p>abc</p>} />
<Route element={<MyComponent />}></Route>
</Routes>
const MyComponent = () =>
<Routes>
<Route path='/def' element={<p>def</p>} />
</Routes>
In this example, navigating to "/def" gives the error:
No routes matched location "/def"
If I add path='*' to the route referencing MyComponent then it works OK, but it seems the documentation is telling me I don't need to do this (and in fact the docs don't mention path='*' as far as I can see).
So why doesn't this work?
const App = () => <Routes> <Route path='/abc' element={<p>abc</p>} /> <Route element={<MyComponent />}></Route> </Routes> const MyComponent = () => <Routes> <Route path='/def' element={<p>def</p>} /> </Routes>
I think you are conflating what layout routes do with nested routes with descendent routes that any routed component can render further down the ReactTree. A pathless layout route like this doesn't participate in route matching, so it's expecting nested routes to be declared so that they can participate.
const App = () =>
<Routes>
<Route path='/abc' element={<p>abc</p>} />
<Route element={<MyComponent />}>
{/* no nested routes to match 🤷🏻♂️ */}
</Route>
</Routes>
When using layout routes you directly wrap and render nested routes. Layout routes serve the purpose of generally providing some "common UI" and an Outlet for the nested routes to render their content into.
Example using layout routes.
const App = () => (
<Routes>
<Route path='/abc' element={<p>abc</p>} />
<Route element={<MyComponent />}> // <-- parent route
<Route // <-- nested route
path='def' // <-- "/def"
element={<p>def</p>} // <-- rendered into Outlet
/>
</Route>
</Routes>
);
const MyComponent = () => (
<div>
{/* Common UI header, etc */}
<Outlet />
{/* Common UI footer, etc */}
</div>
);
Layout routes play a non-existent role when rendering descendent routes.
One very important distinction though is that in order for descendent routes to be reachable and matchable the parent route must append the wildcard matcher, or splat, to its path.
Descendent routes build their paths relative to their parent route. This is why your code worked when you added path="*" to the parent route. This will match anything by "/abc" which is matched by the first route.
Example using descendent routes.
const App = () => (
<Routes>
<Route path='/abc' element={<p>abc</p>} />
<Route // <-- parent route
path="*" // <-- match anything but "/abc"
element={<MyComponent />}
/>
</Routes>
);
const MyComponent = () => (
<div>
{/* Common UI header, etc */}
<Routes>
<Route // <-- descendent route
path='def' // <-- "/" + "def" -> "/def"
element={<p>def</p>}
/>
</Routes>
{/* Common UI footer, etc */}
</div>
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With