Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I exactly match routes nested deeply in react router 6?

How can I match the full route with path "users/:id/settings" but at the same time render only the component in each path:

  • /users -> only renders a list of users
  • /users/:id -> only renders the user profile
  • /users/:id/settings -> only renders the user settings.

     <Route path="users" element={<h2>LIST PROJECTS</h2>}>
       <Route path=":id" element={<h2>PROJECT id</h2>}>
          <Route path="settings" element={<h2>PROJECT SETTINGS</h2>} />
        </Route>
     </Route> 
like image 342
Stephanos Avatar asked Sep 01 '25 20:09

Stephanos


1 Answers

I've solved this by:

  1. Creating index routes ("/") to encapsulate the children like so:
    - /              // Level 1 routes index route
    - users          // level 1 route
       - /             // Level 2 routes index route                  
       - :id           // level 2 route
       - settings      // level 2 route

    - posts          // level 1 route
       - /             // Level 2 routes index route
       - :id           // level 2 route
       - settings      // level 2 route
       - ...

I think of Level 1 routes as my app's data collections (users, posts etc) and level 2 routes as any sub-routes that relate to a specific item within that higher level collection (:userId, settings etc)

  1. Using the <Outlet /> component from react-router-v6 as the element to-be-rendered in each parent route. The Outlet is responsible for rendering all the children components of the children routes under that index, so we use element={<Outlet />} on the index route instead of rendering a React component directly.

Here is an example with index routes rendering an Outlet component:

          <Route path="users"element={ <Outlet /> } >
            <Route path="/" element={<h2>LIST USERS</h2>} />
            <Route path=":id" >
               <Route path="/" element={<React.Fragment>
                                         <h2>USER id</h2>
                                         <Outlet />
                                       </React.Fragment>} />
               <Route path="settings" element={<h2>USER SETTINGS</h2>} />
            </Route>
          </Route>

Here is a more complete approach using the useRoutes hook with which we can write the same configuration more cleanly as a simple JS object:


    import {Outlet, useRoutes} from "react-router-dom"
    
    const App = () => {

      let routeElement = useRoutes([
        {
          path: "/",
          element: <GlobalPageTemplate />,
          children: [
            {
              path: "users",
              element: <Outlet />,
              children: [
                { path: "/", element:<h1>LIST USERS <h1/> },
                {
                  path: "/:id",
                  children: [
                    { path: "/", element: <h1>USER ID</h1> },
                    { path: "/settings", element: <h1>USER SETTINGS</h1> },
                  ],
                },
              ],
            },
            {
              path: "posts",
              element: <Outlet />,
              children: [
                { path: "/", element: <h1>LIST POSTS</h1> },
                {
                  path: "/:id",
                  children: [
                    { path: "/", element: <h1>POST ID</h1> },
                    { path: "/settings", element: <h1>POST SETTINGS</h1> },
                  ],
                },
              ],
            },
            {
              path: "teams",
              element: <Outlet />,
              children: [
                { path: "/", element: <h1>LIST TEAMS</h1> },
                {
                  path: "/:id",
                  children: [
                    { path: "/", element: <h1>TEAMS ID</h1> },
                    { path: "/settings", element: <h1>TEAM SETTINGS</h1> },
                  ],
                },
              ],
            },
          ]
        }
      ]);
    
      return routeElement
    }
like image 180
Stephanos Avatar answered Sep 06 '25 16:09

Stephanos