skip to Main Content

I have a route:

<Route path="/users/:userId?/:edit?" element={(<Users />)} />

Users is a layout component where I deside what to render based on params.
I have a 2 options in this component:

  1. If there’re no params, then render UsersList component.
  2. If there is param userId, then render UserPage component.

Inside UserPage I have simular logic:

  1. if there’re no params, beside userId, then UserPage component is rendered.
  2. if there is param 'edit' included, then render UserEditPage component.

Now I wish to fork UserPage params render like

if (editParam) return <UserEditPage />
if (bookmarkParam) return <UserBookmarks />
return justRenderUserPage()

So in my mind this route would look somthing like

<Route path="/users/:userId?/(:edit? || :/bookmakr?)" element={(<Users />)} />

Which is not working case however.

I have some ideas like to create 2 similar routes:

<Route path="/users/:userId?/:edit?" element={(<Users />)} />
<Route path="/users/:userId?/:bookmark?" element={(<Users />)} />

or shorten the route to

<Route path="/users/:userId?" element={(<Users />)} />

and create 2 additional routes inside UserPage component (make subLayout).

But both ways looks kinda ugly to me, so I wonder – is there any "best practice" for that kind of task? I’d like to see how experience devs do/would do it.

2

Answers


  1. I think you’re mixing up two concepts. Don’t you need something like

    <Route path="/users/:userId?/edit" element={(<UserEditPage />)} />
    <Route path="/users/:userId?/bookmark" element={(<UserBookmarks />)} />
    
    Login or Signup to reply.
  2. You can only have 1 route match per URL path that can be matched, and "/users/:userId?/:edit?" and "/users/:userId?/:bookmark?" have the same specificity and thus the same rank score, so only one of them can be matched and rendered.

    If you want to use a single route definition to render a single Users then you would need to split logic based on the value of the specific segments rather than what you decided to name it (because only one segment name is possible!). Update the segment that you want to "fork" on by giving it a better name, e.g. editOrBookmark, and then check in the Users component the value is for that segment, e.g. is it "edit" or "bookmark" or undefined.

    <Route path="/users/:userId?/:editOrBookmark?" element={(<Users />)} />
    

    The Users render logic might look similar to the following:

    const { userId, editOrBookmark } = useParams();
    
    ...
    
    switch(true) {
      case editOrBookmark === "edit":
        return <UserEditPage />;
    
      case editOrBookmark === "bookmark":
        return <UserBookmarks />;
    
      case !!userId:
        return <UserPage />;
    
      default:
        return <UsersList />;
    }
    

    I suspect there’s a way you could also define the above using the routing structure alone.

    Consider the following:

    ...
    <Route path="/users">
      <Route index element={<UsersList />} />
      <Route path=":userId">
        <Route index element={<UserPage />} />
        <Route path="edit" element={<UserEditPage />} />
        <Route path="bookmark" element={<UserBookmarks />} />
    
        {/* Redirect unknown URL paths back to index "/users/:userId" */}
        <Route path="*" element={<Navigate to="." replace />} />
      </Route>
    </Route>
    ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search