React Router Hooks: Exploring How They Work
Tags: react, javascript, tutorial
Published: 2021-04-13 05:43:14

_by author [Michiel Mulders](https://blog.asayer.io/authors/michiel-mulders)_

The React Router is not the same as the router that directs networking data — luckily! However, there are a lot of similarities between a networking router and the React Router. The React Router helps us to navigate users to the correct component. For instance, we can use client-side routing to build a single-page application (SPA) that allows navigation between different pages without refreshing the browser.

In other words, the React Router keeps your UI in sync with the URL. It has a simple API with powerful features like lazy code loading, dynamic route matching, and location transition handling built right in. 

But, there’s much more to discover. This article will dive into React Router hooks. These hooks allow developers to write much cleaner code as they don’t have to write all the boilerplate code like a class component. We can access several hooks, out of the box, such as `useHistory` , `useLocation`, `useParams`, and `useRouteMatch`. For example, the `useHistory` hook gives us access to the `history` object to handle route changes. 

This article will cover the following sections:

- A basic example of the React Router to get you started
- Examples of each React Router hook to understand its use


## 1. Getting Started: Setting Up a React Project

To get started, we need to create a new React app by running the following command in your terminal:


```
npx create-react-app react-router-tutorial

```

This command creates a new project called `react-router-tutorial`. 

Now, let’s modify the `App.js` file. 


```jsx
import React, { Fragment } from "react";
import "./index.css"
export default function App() {
  return (
    <main>
      <nav>
        <ul>
          <li><a href="/">Home</a></li>
          <li><a href="/about">About</a></li>
          <li><a href="/shop">Shop</a></li>
        </ul>
        </nav>
     </main>
  );
}
// Home Page
const Home = () => (
  <Fragment>
    <h1>Home</h1>
    <LoremText />
  </Fragment>
);
// About Page
const About = () => (
  <Fragment>
    <h1>About</h1>
    <LoremText />
  </Fragment>
);
// Shop Page
const Shop = () => (
  <Fragment>
    <h1>Shop</h1>
    <LoremText />
  </Fragment>
);
const LoremText = () => (
  <p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>
)
```


Our code defines three different pages *Home*, *About*, and *Shop*. Moreover, we’ve added a `<nav>` element that takes care of the navigation. If you click on the `/about` link, we want to navigate to the *About* page. To do so, we need to add the `react-router-dom` dependency to our project. Execute the following command in your terminal:


```
npm install --save react-router-dom
```

Now, let’s configure our React Router.

## 2. Setting Up the React Router

First, we need to import the `Router` object into our `App.js` file. Once that is done, we can use the `Router` object to wrap the entire application as we want routing to be available everywhere in our application.

Note that we’ve also refactored the `<a>` tags to the `<Link>` tags React Router offers. First of all, they will save you problems with relative versus absolute paths but more importantly the `<Link>` tag doesn’t trigger a page refresh while the `<a>` tag naturally does.

On top of that, we import the `Route` object to define the mapping between path and component. For instance, the path `/shop` should load the `Shop` component.


```jsx
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
export default function App() {
  return (
    <Router>
      <main>
        <nav>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/shop">Shop</Link></li>
          </ul>
        </nav>

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/shop">
            <Shop />
          </Route>
        </Switch>
      </main>
    </Router>
  );
}
// Home Page
const Home = () => (
  <Fragment>
    <h1>Home</h1>
    <LoremText />
  </Fragment>
);
// About Page
const About = () => (
  <Fragment>
    <h1>About</h1>
    <LoremText />
  </Fragment>
);
// Shop Page
const Shop = () => (
  <Fragment>
    <h1>Shop</h1>
    <LoremText />
  </Fragment>
);
const LoremText = () => (
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>
)
```


Let’s check if the setup works for you by first building the project:


```
npm run build`
```


Next, let’s start the project and open your browser at `http://localhost:3000`.


```
npm run start
```

You should see the navigation, a title, and the Lorem Ipsum text. Make sure to verify if the navigation works for you. 


![Home page after executing npm run start](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yix4svfbmfby41jjeodu.png)

If everything works, let’s explore React Router hooks!


## 3. Configuring React Router Hooks

Let’s explore how we can use the different React Router hooks.

**useHistory**
The first hook `useHistory` allows us to access the `history` object. We can then call methods on the `history` object like `goBack` or `push`. The `goBack` method allows us to route the user to the previous route in the history stack. For instance, if the user navigates from the `Home`  page to the `Shop` page and then clicks the button to go back, they’ll be redirected to the `Home` page again. 

On the other hand, we can add new entries to the history stack and make the user navigate to this route by using the `push` method.

Here’s the final code that implements a “Go Back” button for the `About` page. Don’t forget to import the `useHistory` hook from `react-router`.


```jsx
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import { useHistory } from "react-router";

// About Page
const About = () => {
    const hist = useHistory();
    return (
        <div>
            <h1>About</h1>
            <button onClick={() => hist.goBack()}>Go Back</button>
            <LoremText />
        </div>
    );
};
export default function App() {
  return (
    <Router>
      <main>
        <nav>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/shop">Shop</Link></li>
          </ul>
        </nav>
        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/shop">
            <Shop />
          </Route>
        </Switch>
      </main>
    </Router>
  );
}
// Home Page
const Home = () => (
  <Fragment>
    <h1>Home</h1>
    <LoremText />
  </Fragment>
);
// Shop Page
const Shop = () => (
  <Fragment>
    <h1>Shop</h1>
    <LoremText />
  </Fragment>
);
const LoremText = () => (
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>
)
```


**useParams**
From the [React documentation](https://reactrouter.com/web/api/Hooks/useparams), we can find the following description for `useParams`:


> `useParams` returns an object of key/value pairs of URL parameters. Use it to access `match.params` of the current `<Route>`.

It’s a much cleaner way to access URL parameters. To illustrate this, let’s modify the shop page to accept URL parameters and print the received parameter to the screen.

The first thing we did is importing the `useParams` hook. Next, we have to change the `Shop`  route to accept a URL parameter. By default, we will show the first product ID when clicking the `Link` tag from the navigation. As you can see, we’ve modified the path for the `Shop` route to `/shop/:id`. 


```jsx
<Router>
      <main>
        <nav>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/shop/1">Shop</Link></li>
          </ul>
        </nav>
        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/shop/:id">
            <Shop />
          </Route>
        </Switch>
      </main>
    </Router>
```


Now, we can access the `id` parameter via the `params` object that is returned by the `useParams` hook.

Also, we’ve added the possibility to navigate to the following product ID using a button with the text `Next product`. Here, we use the `push` method exposed by the `history` object from the previous example to push a new entry to the `history` stack. If you use the `Go Back` button, you’ll notice that you are redirected to the previous product IDs. Try it!


```jsx
import React, { Fragment } from "react";
import "./index.css"
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import { useHistory, useParams } from "react-router";

// About Page
const About = () => {
  const hist = useHistory();
  return (
    <div>
      <h1>About</h1>
      <button onClick={() => hist.goBack()}>Go Back</button>
      <LoremText />
    </div>
  );
};

const Shop = () => {
  const params = useParams();
  const current = params.id;
  const next = Number(current) + 1;
  const hist = useHistory();
  return (
    <div>
      <h1>Shop</h1>
      <p>You requested item with ID: {current}</p>
      <button onClick={() => hist.goBack()}>Go Back</button>
      <button onClick={() => hist.push(`/shop/${next}`)}>Next product</button>
    </div>
  );
};

export default function App() {
  return (
    <Router>
      <main>
        <nav>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/shop/1">Shop</Link></li>
          </ul>
        </nav>
        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/shop/:id">
            <Shop />
          </Route>
        </Switch>
      </main>
    </Router>
  );
}
// Home Page
const Home = () => (
  <Fragment>
    <h1>Home</h1>
    <LoremText />
  </Fragment>
);
const LoremText = () => (
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>
)

```

That’s it for the `useParams` React Router hook!

**useLocation**
The `useLocation` hook returns the location object that represents the current URL. You can think about it like a `useState` that returns a new location whenever the URL changes. You can use it, for instance, to trigger a new page view event for a web analytics tool.

Here’s a modified example of the `About` component that prints the pathname. Every time you visit the `About` page, the path `/about` will be printed to the console.


```jsx 
import { useHistory, useLocation, useParams } from "react-router";

// About Page
const About = () => {
  const hist = useHistory();
  const location = useLocation();
  // Fictive call to Google Analytics
  // ga.send(["pageview", location.pathname])
  console.log(location.pathname);
  return (
    <div>
      <h1>About</h1>
      <button onClick={() => hist.goBack()}>Go Back</button>
      <LoremText />
    </div>
  );
};
```


Furthermore, we can even retrieve the query parameters via the `useLocation` router hook. The returned `location` object contains a `search` field which contains the query string. Now, if you use simple `key=value` query strings and you do not need to support IE 11, you can use the browser's built-in `URLSearchParams` API. This API exposes several methods for verifying if the query string contains a certain key (using `has`) but we want to retrieve a query parameter using the `get` function.

Let’s modify the `Link` for the About page in our router from `/about` to `/about?param=text`.


```
<Link to="/about?param=text">About</Link>

```

Now, let’s retrieve the value for the parameter called `param` using the below code:


```jsx
console.log(new URLSearchParams(location.search).get("param")); // result: "text"
```


The code for the `About` function looks like this.


```jsx
// About Page
const About = () => {
  const hist = useHistory();
  const location = useLocation();
  // Fictive call to Google Analytics
  // ga.send(["pageview", location.pathname])
  console.log(location.pathname);
  console.log(location.search);
  console.log(new URLSearchParams(location.search).get("param")); // "text"
  return (
    <div>
      <h1>About</h1>
      <button onClick={() => hist.goBack()}>Go Back</button>
      <LoremText />
    </div>
  );
};
```


**useRouteMatch**
The React Router docs define the `useRouteMatch` as follows:


> The `useRouteMatch` hook attempts to [match](https://reactrouter.com/web/api/match) the current URL in the same way that a `<Route>` would. It’s mostly useful for getting access to the match data without actually rendering a `<Route>`.

In our example, we will use the route match pattern for the Shop page. If the URL doesn’t contain an ID (`/shop`) then we render all products. Else, if it contains an ID (`/shop/:id`) we render the specific product. Without the route match hook, we need to use a Switch statement to render both pages. Now, we can check which route matches and render the correct page.

Make sure first to import the `useRouteMatch` hook. Then we pass the path we want to verify to the `useRouteMatch` hook: `/shop/:id`. If the route matches, we render the product page. We can access the product ID via `routeMatch.params.id`.


```jsx 
const Shop = () => {
  const hist = useHistory();
  const routeMatch = useRouteMatch("/shop/:id");

  // Use match to render the correct page
  return routeMatch ? (
    <div>
      <h1>Shop</h1>
      <p>You requested item with ID: {routeMatch.params.id}</p>
      <button onClick={() => hist.goBack()}>Go Back</button>
    </div>
  ) : (
    <div>
      <h1>Shop</h1>
      <p>All products</p>
      <br />
      <button onClick={() => hist.goBack()}>Go Back</button>
    </div>
  );
};
```


Now, let’s modify the Router to include an extra link that redirects us to the Shop overview page. Both the `/shop` and `/shop/1` links are connected to the `<Shop />` component, without using a `Switch` statement. A single `Route` element is sufficient, with a path set to `/shop`.


```jsx
export default function App() {
  return (
    <Router>
      <main>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about?param=text">About</Link>
            </li>
            <li>
              <Link to="/shop">Shop</Link>
            </li>
            <li>
              <Link to="/shop/1">Product 1</Link>
            </li>
          </ul>
        </nav>

        <Route path="/shop">
          <Shop />
        </Route>

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
        </Switch>
      </main>
    </Router>
  );
}
```

# Observability for Production React Apps

Debugging React apps in production may be challenging and time-consuming. Asayer is a frontend monitoring tool that replays everything your users do and shows how your app behaves and renders for every issue. It’s like having your browser’s inspector open while looking over your user’s shoulder.

![Asayer Frontend Monitoring](https://asayer-content.s3.eu-central-1.amazonaws.com/eb8f28fc4852447eb750d1747c53e692.png)

Asayer helps to quickly get to the root cause by reproducing issues as if they happened in your own browser. It also monitors your frontend performance by capturing key metrics such as page load time, memory consumption and slow network requests as well as *Redux* actions/state.

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://asayer.io/register.html).


That’s it!

If you want to learn more about React Router hooks, make sure to check out the code examples in the [React Router documentation](https://reactrouter.com/web/api/Hooks/). 

→ **The completed code can be found at** [**CodeSandBox.io**](https://codesandbox.io/s/recursing-stonebraker-qfvxe?fontsize=14&hidenavigation=1&theme=dark)**.**