Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to render a NotFound page for all the nested routes in react-router-dom?

I am using React Router DOM v6, the latest version as of 2022.

I have multiple files and layer of folders in my code:

.
└── src/
    └── routes/
        └── Users/
            ├── ViewUser/
            │   └── ViewUserRoutes.js
            └── UserRoutes.js

UserRoutes.js:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import PageNotFound from '../../components/PageNotFound'
import ViewUserRoutes from './ViewUser/ViewUserRoutes.js'

export default function UserRoutes(){
  return(
    <Routes>
      <Route path="/" element={<AllUsers />}/>
      <Route path="/:id/*" element={<ViewUserRoutes />}/>
      <Route path="*" element={<PageNotFound/>}/>  {/* 👈 here */}
    </Routes>
  )
}

ViewUserRoutes.js:

import PageNotFound from '../../../components/PageNotFound'

export default function UserRoutes(){
  return(
    <Routes>
      <Route path="/" element={<ViewUserById />}/>
      <Route path="*" element={<PageNotFound/>}/> {/* 👈 here */}
    </Routes>
  )
}

I want to render a <PageNotFound /> component when the user navigates to a page not defined in any of my routes.

What I’m doing here, is that whenever I define a new <Routes />, I will to explicitly define a route called <Route path="*" element={<PageNotFound />} />. Which is kind-a annoying and makes me feel wrong.

Isn’t there something simple as:

index.js

<BrowserRouter fallback={<PageNotFound />}> {/* 👈 something simple like this */}
  <Route path="users/*" element={<UserRoutes />} />
  {/* ... etc ...etc  */}
</BrowserRouter>

Or do I have to repeat that line of code every time I create a new resource in my app?

>Solution :

What I’m doing here, is that whenever I define a new , I
will to explicitly define a route called <Route path="*" element={<PageNotFound />} />. Which is kind-a annoying and makes me
feel wrong.

I don’t disagree that it can feel annoying, or perhaps less DRY, but it’s by design. Each Routes component is matching its Route children against the URL path and the derived path to itself, so each needs to render a "catch all" route for anything they don’t handle at their level.

Or do I have to repeat that line of code every time I create a new
resource in my app?

Yes, basically. Each Routes component handles its own matching. Keep in mind that while the route JSX may look the same, it’s not actually a duplicate route.

If you want to avoid needing to render duplicate PageNotFound components you can use a single routing configuration with nested routes instead of the split configuration with descendent routes.

Example:

<Routes>
  <Route path="/" element={<AllUsers />} />
  <Route path="/:id">
    <Route index element={<ViewUserRoutes />} />
    <Route path="foo" element={<ViewUserRoutes />} />
  </Route>
  <Route path="*" element={<PageNotFound />} />
</Routes>

If user attempts to navigate to "/1234/bar" there isn’t a route that matches other than the catch-all that renders the <PageNotFound />.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading