Is it possible to render different components depending on a url params value within the same url in react-router-dom?

Viewed 1015

So basically title is my question. Is it possible to achieve something like this with only url paramater change:

<Route path={'/users/:id'} component={()=> UsersPage}/>

<Route path={'/users/:filterOption'} component={()=> UsersList}/>

2 Answers

react-router-dom@5

Yes, absolutely you can. The Router component inclusively matches and renders routes (as opposed to the Switch component that exclusively matches them). This means the Router will render all routes and redirects that are matched by the path prop.

Given path `"/users/someValue":

<Router>
  <Route path={'/users/:id'} component={()=> UsersPage}/>
  <Route path={'/users/:filterOption'} component={()=> UsersList}/>
</Router>

Both components can be matched and rendered.

Note about Route component prop!

Route render methods

When you use component (instead of render or children) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop.

This means you should not use the component prop if you are providing a function. Instead do one of the following

<Router>
  <Route path={'/users/:id'} component={UsersPage}/>
  <Route path={'/users/:filterOption'} component={UsersList}/>
</Router>

or

<Router>
  <Route path={'/users/:id'} render={()=> <UsersPage />}/>
  <Route path={'/users/:filterOption'} render={()=> <UsersList />}/>
</Router>

or

<Router>
  <Route path={'/users/:id'}>
    <UsersPage />
  </Route>
  <Route path={'/users/:filterOption'}>
    <UsersList />
  </Route>
</Router>

react-router-dom@6

react-router-dom@6 now always exactly matches and uses a path ranking/scoring system and '/users/:id' and '/users/:filterOption' have the same specificity and will have the same score. There's nothing to disambiguate between them. Instead you'll rendering a single route and need to use the useParams hook to read the route param, either in a wrapper component or directly in the routed components.

Example with wrapper component.

const UserWrapper = () => {
  const { id } = useParams();
  return (
    <>
      <UsersPage id={id} />
      <UsersList filterOption={id} />
    </>
  );
};

...

<Router>
  <Routes>
    <Route path={'/users/:id'} element={<UserWrapper />} />
    ...
  </Routes>
</Router>

Yes, we can do that in react-router, Just check this article, it has best example for Dynamic URL Parameters.

Related