DEV Community

Shivam Chahar
Shivam Chahar

Posted on • Edited on

Navigation in React Router 6

This was originally posted on Saeloun's blog.

While there are a lot of 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");
  }}
/>
Enter fullscreen mode Exit fullscreen mode

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.

Navigation

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 enables 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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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.

P.S. This is my first ever blog here. Your feedback is highly appreciated 🙏 😄

Top comments (0)