Navigation in React Router 6


While there are different libraries available for client-side routing, React Router is almost always the default choice.

Why React Router?

As the user navigates, the browser keeps track of each location in a stack. That is how the back and forward buttons work.

For example, consider the user:

  1. Clicks a link to /blog
  2. Clicks a link to /categories
  3. Clicks the back button
  4. Clicks a link to /contact

The history stack will change as follows, where the highlighted entries denote the current URL.

  1. /blog
  2. /blog, /categories
  3. /blog, /categories
  4. /blog, /contact

If we click and hold the back button in a browser, we can see the browser’s history stack right there.

Now, some of us might argue that we don’t necessarily need a library to manipulate the history stack. We can do that programmatically like so:

<a
  href="/blog"
  onClick={event => {
    // stop the browser from changing the URL
    event.preventDefault();
    // push an entry into the browser history stack and change the URL
    window.history.pushState({}, undefined, "/blog");
  }}
/>

While the above code changes the URL. It doesn’t do anything about the UI. We will still need to subscribe to the changes in the history stack to show the correct UI on /blog.

Read more about browser’s History API.

React Router makes it easier for us to subscribe to the changes in the browser’s history stack. It also allows us to manipulate the history stack.

React Router provides us with an easy-to-use interface for navigation.

We can use:

  1. <Link> and <NavLink>, which renders an <a> element. We can initiate navigation by clicking on it.
  2. useNavigate and <Navigate> which will enable us to navigate programmatically.

Let us look at <Link> and <NavLink> and their usage.

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

function Navbar() {
  return (
    <nav>
      <Link to="blog">Blog</Link>
      <Link to="categories">Categories</Link>
      <Link to="contact">Contact</Link>
    </nav>
  )
}

We can use <NavLink> in the above example instead of <Link>.

The difference between the two is that <NavLink> knows whether or not it is “active”. So if we want to apply some styles to the active link, we need to use <NavLink>.

Read more about NavLink.

Now, consider a scenario where we want to navigate our users to /dashboard after they successfully log in. This is exactly the place where we would want to navigate programmatically.

React Router provides us useNavigate and <Navigate> to do exactly that.

Let us see how we can use them:

import React, { useState } from "react";
import { useNavigate } from "react-router-dom";

function LoginForm() {
  const [user, setUser] = useState(null);
  const [error, setError] = userState(null);
  const navigate = useNavigate();

  const handleSubmit = event => {
    event.preventDefault();
    try {
      const user = await login(event.target);
      setUser(user);
      navigate("/dashboard", { replace: true });
    } catch (error) {
      setError(error);
    }
  }

  return (
    <div>
      {error && <p>{error.message}</p>}
      <form onSubmit={handleSubmit}>
        <input type="text" name="username" />
        <input type="password" name="password" />
        <button type="submit">Login</button>
      </form>
    </div>
  );
}

Alternatively, we can also use <Navigate> like this:

import React, { useState } from "react";
import { Navigate } from "react-router-dom";

function LoginForm() {
  const [user, setUser] = useState(null);
  const [error, setError] = userState(null);

  const handleSubmit = event => {
    event.preventDefault();
    try {
      const user = await login(event.target);
      setUser(user);
    } catch (error) {
      setError(error);
    }
  }

  return (
    <div>
      {error && <p>{error.message}</p>}
      {user && (
        <Navigate to="/dashboard" replace={true} />
      )}
      <form onSubmit={handleSubmit}>
        <input type="text" name="username" />
        <input type="password" name="password" />
        <button type="submit">Login</button>
      </form>
    </div>
  );
}

With this, we do not have to worry about manipulating the history stack and subscribing to its changes. React Router handles all of that for us!

React Router 6 provides a few low-level APIs that can be useful while building our navigation interfaces -

Check out the React Router 6 API doc to learn more.

Join Our Newsletter