Kushank Sriraj
Kushank's web

Kushank's web

Easy guide to React Router v6: Use it in your next project!

Easy guide to React Router v6: Use it in your next project!

Kushank Sriraj's photo
Kushank Sriraj
Β·Jun 15, 2021Β·

6 min read

I know it's in beta but it's worth trying! If you don't know what the router does in React, I suggest you read more about it and then follow this guide to be updated with the latest version of it: v6.

Improvements

Why should you use it? Because you don't wanna miss these amazing features:

  • 70% less in bundle size in comparison to v5
  • No need to use exact prop on every route
  • Relative paths, nested routes and layouts
  • useNavigate hook for programmatically navigating

And much more...

Let's see some newer APIs

1. <BrowserRouter>

This is the interface for running React router in a web browser (there is another interface for React Native apps).
Take a look at the below code in index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from "./App"
import { BrowserRouter } from 'react-router-dom';

const root = document.getElementById("root");
ReactDOM.render(
  <BrowserRouter>
      <App />
  </BrowserRouter>,
  root
);

I like to think in terms of context APIs when I see this syntax. If you can relate, this makes understanding easy. It infers that the App is wrapped in the router interface so that we can use router APIs inside App or its children.

2. <Routes> and <Route>

This is helpful when you are doing routing from the JSX part of your react component.

<Routes>
  <Route path="/" element={ <Home /> } />
  <Route path="/contact" element={ <Contact /> } />
  <Route path="/about" element={ <About /> } />
</Routes>

The above code looks intuitive and self-explanatory. There are three routes defined which when triggered, renders three different components. The routes are basically mount points that mount or unmount components based on the URL.

2. <Link> and <NavLink>

React Router provides these components for changing routes on click. Both are accessible HTML <a> tag.

import React from 'react';
import { Link } from 'react-router-dom';

export const NavBar = () => {
  return (
    <nav>
      <Link to="/about"> ABOUT </Link>
      <Link to="/contact"> CONTACT </Link>
    </nav>
  )
}

This is very helpful in quickly setting up navigation in your app.
The NavLink component is similar to Link with just one difference, it knows whether it is active or not. It can change styles based on this.

import React from 'react';
import { NavLink } from 'react-router-dom';

export const NavBar = () => {
  return (
    <nav>
      <NavLink to="/about" activeStyle={{ color: "blue" }}> ABOUT </NavLink>
      <NavLink to="/contact" activeStyle={{ color: "blue" }}> CONTACT </NavLink>
    </nav>
  )
}

Here, the color of the link text will change to blue if that link is clicked. Much better than the basic Link component.

3. useNavigate hook

This hook lets you programmatically navigate to a particular route. This is the backbone of many apps that I've built, it makes your life easy.

import { useNavigate } from 'react-router-dom';
import { subscribeUser } from "./helper";

export const SubscriptionForm = () => {
  const navigate = useNavigate();

  const handleSubmit = async (event) => {
    event.preventDefault();
    await subscribeUser(event.target[0].value);
    navigate("/confirm-subscription");
   }

  return (
    <form onSubmit={handleSubmit}>
       <input type="email" />
       <button type="submit"> Subscribe </button>
    </form>
  );
}

A simple example, where we navigate to the "confirm-subscription" route on submitting the form.

4. useLocation hook

This hook returns the current location object, which represents the current URL in web browsers. You can use this hook to do your own kind of routing, track URL changes, etc.

import React from 'react';
import { NavLink, useLocation } from 'react-router-dom';

const NavBar = () => {
  const location = useLocation();

  return (
    <nav>
      <h2>You are in { location.pathname } route</h2>
      <NavLink to="/about" activeStyle={{ color: "blue" }}> ABOUT </NavLink>
      <NavLink to="/contact" activeStyle={{ color: "blue" }}> CONTACT </NavLink>
    </nav>
  )
}

5. useParams hook

This hook lets you access the URL params specified in the routes. This is extremely helpful when building an app like E-commerce where you need to have pages for each product.

  <Route path="/product/:id" element={ <ProductPage /> } />

Here, we have an id in our route which we can access as below:

import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { fetchProductById } from "./helper";

export const ProductPage = () => {
  const { id } = useParams();
  const [product, setProduct] = useState({});

  useEffect(() => {
    (async () => {
      const res = await fetchProductById(id);
      setProduct(res.data.product);
    })();
  }, [id]);

  return (
    <article>
      <header>{product?.title}</header>
      <img src={product?.image} alt={product.title} />
      <div>{product?.price}</div>
      <p>{product?.description}</p>
    </article>
  );
};

Here, we fetch the product details based on the id we got from the useParams hook.

Other useful features

1. 404 Page

Whenever your apps have multiple routes, it's crucial to set up the 'Page Not Found' route. Here is how to do that with React Router.

  <Route path="*" element={ <PageNotFound /> } />

This route will capture all paths and render the PageNotFound component. The trick is to place this route component at the last, after all other route components.

import React from 'react';
import { Link } from 'react-router-dom';

const PageNotFound  = () => {

  return (
    <div>
        <h2>404 Page Not Found!</h2>
        <h3>Go to <Link to="/"> Home page </Link></h3>
    </div>
  )
}

Here, we let the user go to the home page using Link.

2. <PrivateRoute> for protected routes

When we add authentication to our apps, we need to make sure the protected routes like payment, profile, etc, are only accessible by authorised users. If an unauthorised user tries to open that route, we just redirect the user to the login page.

import React from 'react';
import { Navigate, Route} from 'react-router-dom';
import { useAuth } from "./useAuth";

export const PrivateRoute = (props) => {
  const { isUserLoggedIn } = useAuth();

  if(isUserLoggedIn) {
   return <Route {...props} />
  }

  return <Navigate to="/login" />
}

Now, we can use PrivateRoute to protect our routes. Check out what <Navigate /> does.

<Routes>
  <Route path="/" element={ <Home /> } />
  <Route path="/login" element={ <Login /> } />
  <PrivateRoute path="/payment" element={ <Payment /> />
  <PrivateRoute path="/profile" element={ <Profile /> />
</Routes>

3. replace argument

React Router uses the HTML5 History API for routing and history is implemented as a stack. Yes, the data structure stack.
So, we have the option to pop the top element, replace the top element and add a new element on the top.
When we navigate from one page to another, the path we navigated to, is added on top of the stack, the previous path stays just below the current path. If we press the back button of the browser, the current path is popped off and the previous path is loaded.

Consider a scenario where an unauthorised user goes from the home page to the profile page. So, we redirect the user to the login page. The user logs in and is redirected to the profile page. When the user clicks the back button, he will go to the login page again. This should not happen as the user is already logged in.

We can solve this problem using the replace argument in route navigation APIs like Link, Navigate, NavLink and useNavigate.

import { useNavigate } from 'react-router-dom';
import { logInUser } from "./helper";

export const Login = () => {
  const navigate = useNavigate();

  const handleSubmit = async (event) => {
    event.preventDefault();
    const email = event.target[0].value;
    const password = event.target[1].value;
    const res = await logInUser({ email, password });
    if(res.data.success){
        navigate("/profile", { replace: true });
      }
   }

  return (
    <form onSubmit={handleSubmit}>
       <input type="email" />
       <input type="password" />
       <button type="submit"> Login </button>
    </form>
  );
}

You can also pass state variables via the navigation APIs. I will probably write another post on that.

I hope this post helps you in using the latest React Router in your projects. Feel free to comment with your questions, or just drop a hi! Let me know what you learned from this post.

Don't forget to check out the official API reference.

Keep routing your apps! See ya πŸšΆβ€β™‚οΈ

Β 
Share this