A new rendering pattern

React Router 5 ships four hooks for routing work. Before getting to them, it helps to look at how route rendering changed.

The component and render props

// When you wanted to render the route and get router props for component
<Route path="/" component={Home} />


// Or when you wanted to pass extra props
<Route path="/" render={({ match }) => <Profile match={match} mine={true} />}>

With the component syntax, route props — match, location and history — reach the component implicitly. As soon as you need to hand the component extra props, you must switch to render. Wrapping the component syntax in an inline function instead causes the component to re-mount on every render.

Routes without implicit props

<Route path="/">
  <Home />
</Route>

Nothing is passed implicitly to Home here, yet extra props can be attached to it without touching the Route itself. The re-mount mistake disappears.

Accessing match, history or location now falls to the hooks rather than to withRouter wrapping. Hooks require React 16.8 or above.

  • Gives access to the history prop.
  • Exposes the history package the router depends on.
  • Suited to programmatic routing via functions such as push and replace.

Reading the router state

useLocation

  • Gives access to the location prop.
  • Resembles window.location, but is available anywhere because it represents router state and location.
  • Typically used for query params or the full route string.
import { useLocation } from 'react-router-dom';

function Profile() {
  const location = useLocation();
  useEffect(() => {
    const currentPath = location.pathname;
    const searchParams = new URLSearchParams(location.search);
  }, [location]);
  return <p>Profile</p>;
}

Because location is immutable, a useEffect wrapping it fires on every route change — a good fit for acting on search parameters or the current path.

useParams

  • Gives access to the search parameters in the URL.
  • Previously only reachable through match.params.
import { useParams, Route } from 'react-router-dom';

function Profile() {
  const { name } = useParams();
  return <p>{name}'s Profile</p>;
}

function Dashboard() {
  return (
    <>
      <nav>
        <Link to={`/profile/ann`}>Ann's Profile</Link>
      </nav>
      <main>
        <Route path="/profile/:name">
          <Profile />
        </Route>
      </main>
    </>
  );
}

useRouteMatch

  • Gives access to the match object.
  • Called with no arguments, it returns the closest match in the component or its parents.
  • Typically used to build nested paths.
import { useRouteMatch, Route } from 'react-router-dom';

function Auth() {
  const match = useRouteMatch();
  return (
    <>
      <Route path={`${match.url}/login`}>
        <Login />
      </Route>
      <Route path={`${match.url}/register`}>
        <Register />
      </Route>
    </>
  );
}

Called with a location argument, the hook returns a match without rendering a Route at all.

Take a profile that should render your own page at /profile and someone else's at /profile/dan or /profile/ann. The pre-hook approach meant writing a Switch, listing both routes and customising them with props. The hook version:

import {
  Route,
  BrowserRouter as Router,
  Link,
  useRouteMatch,
} from 'react-router-dom';

function Profile() {
  const match = useRouteMatch('/profile/:name');

  return match ? <p>{match.params.name}'s Profile</p> : <p>My own profile</p>;
}

export default function App() {
  return (
    <Router>
      <nav>
        <Link to="/profile">My Profile</Link>
        <br />
        <Link to={`/profile/ann`}>Ann's Profile</Link>
      </nav>
      <Route path="/profile">
        <Profile />
      </Route>
    </Router>
  );
}

Route props such as exact or sensitive can also be supplied as an object to useRouteMatch.

Why the explicit style pays off

Across repeated workshops, the combination of these hooks with an explicit Route has measurably cut down on the confusion and intricacy of the older patterns; unforced errors are far rarer. Router code stays more maintainable, and upgrading to later React Router versions gets easier.