Using React Router v6 with React

Varun KelkarVarun Kelkar
7 min read

What is React Router?

React Router is a Javascript Library that allows us to handle Client Side & Server Side routing in React Apps.

It enables the creation of single-page web or mobile apps that allow navigating without refreshing the page.

It also allows us to use browser history features while preserving the right application view.

What's so different with v6?

If you've been following React Router for a long time, you would already know that until v6, it was fairly easy to use this library.

From v6 onwards, they introduced a plethora of features.

So now it's not that easy to understand this library. It requires a bit of trial & error to get your React app working as expected.

Prerequisites

Working knowledge of React.

Some basic understanding of React Router would be awesome but not mandatory.

Let's Get Started

Essentially what React Router does is, it renders a Component for a given Route.

This is the basic purpose of React Router.

To learn React Router, let's develop a React App.

I'll be covering client-side routing in this blog.

Creating a React App

Let's create a boilerplate React app using the below command.

npx create-react-app react-router-demo

Post running this command, you should be able to see boilerplate code like below.

Run the below command to verify the correct installation of React App.

cd react-router-demo
npm start

If all goes well, you should be able to see below mentioned page.

Installing React Router

By default, CRA Template does not provide React Router package.

We need to install it explicitly.

Stop your app & run the below command to install React Router.

npm install react-router-dom@latest

Writing routes configuration

Let's plan our routes.

We'll have the following routes in the app.

  • /home

  • /products

  • /products/:id

Create Components for Landing Page, Home, Products & Product page. I'll leave the component design up to you.

Create a file called AppRoutes.ts inside the src folder.

Let's write a routes config inside this file.

// Add import statements for your App, LandingPage, Home, Products & Product page
const routes = [
  {
    path: "/",
    element: <App />,
    children: [
      {
        index: true,
        element: <LandingPage />,
      },
      {
        path: "/home",
        element: <Home />,
      },
      {
        path: "/products",
        children: [
          {
            index: true,
            element: <Products />,
          },
          {
            // id is a placeholder
            // Value of id is not known at the time of writing config
            // How to access value of id is shown at end of article
            // syntax - :<place-holder-name>
            path: "/products/:id",
            element: <Product />,
          },
        ],
      },
    ],
  },
];
export default routes;

Let me explain the structure of the routes array.

The general syntax goes like below.

const routes = [
 {
    path: "<your-root-path>",
    element: <root-component/>,
    children: [
      {
        path: "/<path-one>",
        element: <component-to-be-rendered-on-that-path/>
      },
      {
        path: "/<path-two>",
        element: <component-to-be-rendered-on-that-path/>,
         // every route need not have children. It's optional.
        children: [
          {
            path: "/<path-two>/<nested-path-one>",
            element: <component-to-be-rendered-on-that-path/>,
          },
          {
            path: "/<path-two>/<nested-path-two>",
            element: <component-to-be-rendered-on-that-path/>,
            // every route need not have children. It's optional.
            children: [
               // ...more children routes
            ]
          },
          // ...other children routes
        ],
      },
      // ...other parent routes
    ],
  },
  // no other routes should go here
]

You might have a few questions about the configuration we wrote. I've answered a few at the end of this article.

Configuring Router

Now inside your index.js file, you'll have the following content by default.

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Replace that content with the following content.

import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import routes from "./AppRoutes";
import "./index.css";
import reportWebVitals from "./reportWebVitals";

const root = ReactDOM.createRoot(document.getElementById("root"));
const router = createBrowserRouter(
routes,
// Adding base route is optional.
{basename: '<base-route>'}
);

root.render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Understanding Configuration

createBrowserRouter - It's a function provided by react-router-dom. It expects the routes array as an argument & it returns the router config.

We are using client-side routing. So Browser Router is what fits our use case.

RouterProvider - It's a component provided by react-router-dom which expects a router as its prop.

💡
Note - The RouterProvider does not accept any children components. That's why wrapping your App component inside won't work.

On the default route i.e. path: '/', React Router v6 expects a component which controls the layout of your Application.

In our case, the App component controls our layout. It has Header, Navigation components & the rest of the area is for our dynamic components i.e. Home, Products & Product.

Here's a snapshot of what my App Component looks like,

A few commonly asked questions

What is the root path?

The root path is the base URL of your application. It's usually configured while creating router config. In our case, we can configure it in the createBrowserRouter function.

For simplicity, you can also refer to the base URL as '/'. React Router understands it as a base URL.

Who is the root component?

The root component is the one which controls the layout of the application. In my case, the App component controls the layout. It contains Header, Navigation & slot to render other routes.

What is the Outlet component?

The Outlet component acts as a placeholder component for the child components to render. Without using <Outlet/> the child routes will not be rendered.

💡
Each route that has children must contain <Outlet/> component inside it's <Component/>

What is index property?

When we mark any route as an index, the component of that route will only render for that particular route.

Let's try to understand with an example.

const routes = [
...other routes,
{
  path: "/products",
  children: [
  {
    index: true,
    element: <Products />,
  },
  {
    path: "/products/:id",
    element: <Product />,
  },
  ],
 },
]

What would've happened if I wrote the config as below,

const routes = [
...other routes,
{
  path: "/products",
  element: <Products />,
  children: [
  {
    path: "/products/:id",
    element: <Product />,
  },
  ],
 },
]

When we visit '/products', the <Products/> component will render but when we visit '/products/:id', <Products/> & <Product/> both will render.

But we want only <Product/> to render on '/products/:id'

Adding index: true helps us achieve this.

How to navigate between different routes?

For navigating between routes, React Router provides two ways.

One is via a Component & another one is via a navigation hook.

Let's understand with an example.

// Navigating via a navigation hook
import { useNavigate } from "react-router-dom";

const YourComponent = () => {
    const navigate = useNavigate();
    const yourCustomFunction = () => {
    navigate('/<route-name>');
    }
    return <jsx>
}
💡
useNavigate() works only inside a functional component.
// Navgating via Link Component
import { Link } from "react-router-dom";

const YourComponent = () => {

return <div>
    <Link to="/<route-name>"><span>Click to navigate</span></Link>
</div>
}
💡
<Link> works inside the class as well as function components.

How to access dynamic parts of the route?

Did you notice the '/products/:id' route?

:id is just a placeholder. To access its value, use the below-mentioned hook.

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

// This is the component which renders for '/products/:id' route
const YourComponent = () => {
    // The name 'id' should be same in route config as well as here.
    const { id } = useParams();
    const yourCustomFunction = () => {
    console.log(id)
    }
    return <jsx>
}

Conclusion

This was just the basic information about React Router.

React Router is far more vast than this article. But this article is enough to get you started.

0
Subscribe to my newsletter

Read articles from Varun Kelkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Varun Kelkar
Varun Kelkar

Javascript | React | Node | Lit Web Components | Microfrontends