Gaurav Singhal Guarav is a data scientist with a strong background in computer science and mathematics. As a developer, he works with Python, Java, Django, HTML, Struts, Hibernate, Vaadin, Web Scrapping, Angular, and React.

Using Hooks with React Router

5 min read 1590

React Router Hooks

React Hooks were introduced with the release of React 16.8.0 to much excitement. With Hooks, developers can write cleaner components with less boilerplate compared to a class component. Many popular React packages are adding support for Hooks so developers can leverage their APIs in functional components.

React Router, the go-to routing solution for React Apps, added Hooks support in its version 5 release. These React Router Hooks provide developers with new ways to handle the router state.

In this tutorial, we’ll show you how to use Hooks with React Router and minimize code lines in a component.

How Hooks work with React Router

To demonstrate how Hooks work, we’ll create a React project and set up the pages.

To create a React app, run the following command:

npx create-react-app router-hooks-demo

Note that router-hooks-demo is the name of the app for this guide; you can change the name as you wish.

Next, add the react-router-dom package:

npm i react-router-dom --save

Import BrowserRouter, Link, Route, and Switch components from the react-router-dom package. These components will be used to configure client-side routing in the React app.

import { BrowserRouter, Link, Route, Switch } from "react-router-dom";

For this demo, you’ll only have two routes, or pages: the home page and user page. You’ll mainly be working on the user page.

const User = () => {
  return <div>This is the user page</div>;
};

const Home = () => {
  return <div>This is the home page</div>;
};

In the App component, create a navigation bar section and add hyperlinks to the pages using the Link component. On the webpage, the Link component gets rendered as a <a> tag.

We made a custom demo for .
No really. Click here to check it out.

<nav>
  <div>
    <Link to="/">Home</Link>
  </div>
  <div>
    <Link to="/user/:id">User</Link>
  </div>
</nav>

Next, add the Switch and Route component, and wrap everything in the BrowserRouter component.

<BrowserRouter>
  <nav>
    <div>
      <Link to="/">Home</Link>
    </div>
    <div>
      <Link to="/user/:id">User</Link>
    </div>
  </nav>
  <Switch>
    <Route path="/user">
      <User />
    </Route>
    <Route path="/" exact>
      <Home />
    </Route>
  </Switch>
</BrowserRouter>

The BrowserRouter component enables the client-side routing feature and handle the routing logic using the browser history API. The Route component renders the page UI when the route path matches the active URL. The Switch component only allows the first matched path to be rendered.

If you have a bunch of Route components that match the same URL, you’ll end up rendering all the routes, which is not expected. Only one route should be rendered for a URL.

The final App.js file should look like this:

import React from "react";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";

const User = () => {
  return <div>This is the user page</div>;
};

const Home = () => {
  return <div>This is the home page</div>;
};

export default function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <nav>
          <div>
            <Link to="/">Home</Link>
          </div>
          <div>
            <Link to="/user/:id">User</Link>
          </div>
        </nav>
        <Switch>
          <Route path="/user/:id">
            <User />
          </Route>
          <Route path="/" exact>
            <Home />
          </Route>
        </Switch>
      </BrowserRouter>
    </div>
  );
}

Why React Router Hooks are useful

Let’s say you need to access the current pathname of the URL inside a page component. Before Hooks, you would have to pass the page component to the component prop of the Route component. Then the Route component would inject with route props: match, location, and history.

This is fine, but the component becomes harder to read and it’s difficult to understand how the props are injected when it comes to maintaining the project. The React Router authors added Hooks support so the page components can access history, location, and match objects without having to pass the page component as a component prop in the Route component.

// Route with component prop
<Route path="/user/:id" component={User} />;

// User component
const User = (props) => {
  const location = props.location;

  console.log(location.pathname);

  return <div>This is the user page</div>;
};

React Router Hooks

Now that you understand why Hooks are added for routing, let’s see the Hooks in action.

useParams

The useParams Hook returns an object containing key-value pairs of the passed parameters in a dynamic URL.

For example, let’s say you have a User page component that accepts an id as a param in the URL.

<Route path="/user/:id">
  <User />
</Route>

Import the useParam Hook from react-router-dom package.

import { useParams } from "react-router-dom";

Now you can use the Hook, as shown below.

const User = () => {
  const params = useParams();

  console.log(params);

  return (
    // ...
  )
}

So if you were to pass 3 as ID in the user URL (/user/3), the useParam() would return an object as follows:

{
  id: 3,
}

You can use this id param to display on the page or fetch the user information from the server.

import {
  // ...
  useParams,
} from "react-router-dom";

// /user/:id
const User = () => {
  const params = useParams();

  return (
    <div>
      <div>This is the user page</div>
      <div>current user Id - {params.id}</div>
    </div>
  );
};

useHistory

The useHistory Hooks return the history object, which the router uses internally to handle the route changes. The history object is used for managing session history.

For example, you can use the history.push() method to add a new entry to the history stack and navigate the user from the current route:

import {
  // ...
  useHistory,
} from "react-router-dom";

const User = () => {
  const history = useHistory();
  const params = useParams();

  const handleBack = () => {
    history.goBack();
  };

  const handleNavigation = () => {
    history.push("/user/5");
  };

  return (
    <div>
      <div>This is the user page</div>
      <div>current user Id - {params.id}</div>
      <div>
        <button onClick={handleBack}>Go Back</button>
      </div>
      <div>
        <button onClick={handleNavigation}>Go To Different User</button>
      </div>
    </div>
  );
};

In the code block above, two buttons are added to the User page component: one button to take the user to the previous page and another to navigate the user to a different page. The history.goBack() method navigates the user to the previous page and goes back one entry in the history stack.

useLocation

The useLocation Hook allows you to access the location object that represents the active URL. The value of the location object changes whenever the user navigates to a new URL.
The useLocation Hook can be convenient when you have to trigger any event whenever the URL changes.

Consider that you have to keep track of views on users’ profile pages. You can detect changes in the location object using the useEffect Hook, which comes with React.

import {
  // ...
  useLocation,
} from "react-router-dom";

const User = () => {
  const history = useHistory();
  const params = useParams();
  const location = useLocation();

  useEffect(() => {
    console.log(location.pathname);
    // Send request to your server to increment page view count
  }, [location]);

  const handleBack = () => {
    history.goBack();
  };

  const handleNavigation = () => {
    history.push("/user/5");
  };

  return (
    <div>
      <div>This is the user page</div>
      <div>current user Id - {params.id}</div>
      <div>
        <button onClick={handleBack}>Go Back</button>
      </div>
      <div>
        <button onClick={handleNavigation}>Go To Different User</button>
      </div>
    </div>
  );
};

useRouteMatch

The useRouteMatch Hook matches the active URL with a given path, similarly to how the Route component works. It’s a very interesting Hook; you can get rid of the unnecessary Route component and access the match object.

You can now change the path in the user page’s route component to simply /user:

<Route path="/user/">
  <User />
</Route>

Then, use the routeMatch Hook, as shown below:

import {
  // ...
  useRouteMatch,
} from "react-router-dom";

const User = () => {
  const history = useHistory();

  const routeMatch = useRouteMatch("/user/:id");
  const location = useLocation();

  useEffect(() => {
    console.log(location);
  }, [location]);

  const handleBack = () => {
    history.goBack();
  };

  const handleNavigation = () => {
    history.push("/user/5");
  };

  return (
    <div>
      <div>This is the user page</div>
      {routeMatch ? (
        <div>user Id - {routeMatch.params.id}</div>
      ) : (
        <div>You are viewing your profile</div>
      )}

      <div>
        <button onClick={handleBack}>Go Back</button>
      </div>
      <div>
        <button onClick={handleNavigation}>Go To Different User</button>
      </div>
    </div>
  );
};

The useParams hook will not return an empty object since the Route component did not have any route params specified. Instead, you now have access to params in the routeMatch object.

Conclusion

Hooks are a great addition to the React ecosystem. Now that you’ve seen some code on handling routing with Hooks, you’re ready to take full advantage of what they have to offer.

Until next time, stay safe and keep coding with React Hooks!

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Gaurav Singhal Guarav is a data scientist with a strong background in computer science and mathematics. As a developer, he works with Python, Java, Django, HTML, Struts, Hibernate, Vaadin, Web Scrapping, Angular, and React.

One Reply to “Using Hooks with React Router”

  1. I was following this as a codealong, start is a bit confusing maybe add that the changes are made in App.js.
    But I get a compile error at the useEffect() part, until I realized I still had to import it from react.
    I’m just 2 weeks in coding in React, so guess for a beginner they will need some more guidance

Leave a Reply