Routing with React Router 6
Tags: webdev, javascript, react, router
Published: 2022-06-10 11:29:17

by [Amazing Enyichi Agu](https://blog.openreplay.com/authors/amazing-enyichi-agu)


Websites built with Javascript frameworks/libraries like Vue and React JS are Single Page Apps. This means that all the elements on the website are done on a single `index.html` page. But these frameworks have a way of making a page have nested URL routes even though it is built on a single page. These routes make the page easily navigatable with the back and forward buttons of a browser and break the web app into parts.

![Navigation buttons in a browser](https://blog.openreplay.com/static/13c8703e5dde88fbce834b67908625c0/68382/image01.png)

React JS as a Single Page App library doesn't include built-in routing capabilities as Angular does; it needs a library called `react-router-dom` to do this. Now, that library has been in use for a long time, but with a new version (v6) released, a lot of things have been changed in how the library is used.

In this tutorial, we will go over the `react-router-dom` version 6 library and see how to perform many routing tasks. At the end of this tutorial, you should have grasped how `react-router-dom` v6 works and how to use it to create navigation links, pass states through links, redirect pages, create nested pages, protect routes, and so on. We assume that the reader has zero knowledge of the `react-router-dom` library, so the tutorial is easy and accessible to beginners who haven't used previous versions of the library before. On that note, let's get started!

## Starting a Router Project

For a quick setup of a React Application, I recommend starting a new React project at https://stackblitz.com. However, here's a guide on [installing React JS on your local machine.](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app) After that setup, if we are working locally, we must add the `react-router-dom` library. (On Stackblitz, just install the package as a dependency.)

```
npm install react-router-dom@6
```

The `@6` specifies that we are installing version 6 into our project. After the dependency/library is installed, we start our React project.

```
npm start
```

With everything working, we are ready to move over to the next stage.

### Setting up the Router

The first thing we will do on our website is to create a component encompassing all the different routes we will have in our routing system. This component must be placed at the highest level of the App component. So, open up the project in a code editor and navigate to `src/App.js`.

```javascript
import React from "react";
import { BrowserRouter } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
    </BrowseRouter>
  );
}

export default App;
```
In this file, we imported the `BrowserRouter` component, and then we used the component to wrap other things in our App.js. Other types of routers have different purposes, but the [docs](https://https://reactrouter.com/) recommend `BrowserRouter` for web apps.

And now, inside this `BrowserRouter` component, other components and hooks from `react-router-dom` can work.

## Creating Navigation links
Let's create a Header on our website before creating the navigation links.

```javascript
import React from "react";
import {BrowserRouter} from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <header>
        <h1>Hello World</h1>
      </header>
    </BrowseRouter>
  );
}

export default App;
```

We will create some navigation links that will point to some routes inside our `App.js`. These routes are created inside the `App.js` because we want them to be visible on every page. To do that, we must import the `NavLink` component. The `NavLink` component is a link component (similar to the `<a>` tag) that knows whether or not it is "active", meaning it can highlight itself the current page is the page it routes to is on display.

In our `src/App.js`: 

```javascruot
import React from "react";
import { BrowserRouter, NavLink } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <header>
        <h1>Hello World</h1>
      </header>
      <nav>
        <NavLink to="">Home</NavLink>
      </nav>
    </BrowserRouter>
  );
}

export default App;

```
And we should have the picture below on display.

![First version of the app](https://blog.openreplay.com/static/d47717be1d9f2e79b92689c907f98749/e0433/image02.png)

Now, we have a component that points us to the route `/` whenever we click on it. The `to` prop shows the `Navlink` where to go.

We will create some more navigation links using the `NavLink` component.

```javascript
import React from 'react';
import { BrowserRouter, NavLink } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <header>
        <h1>Hello World</h1>
      </header>
      <nav>
        <NavLink to="">Home</NavLink>
        <NavLink to="about">About</NavLink>
        <NavLink to="contact">Contact</NavLink>
      </nav>
    </BrowserRouter>
  );
}

export default App;

```
And now, we will have this displayed.

![Modified app](https://blog.openreplay.com/static/658690e04b896d5c01f013750d6244ae/e0433/image03.png)

These links lead to the routes `/home`, `/about`, and `/contact`. And whenever they are clicked, the URL of the webpage changes conveying the routes.

### Adding the Active Class

The active class merely highlights a link when the page is currently where the link points to. To add it, we first need to define a class that will contain all the styles of our active `NavLink`. The style class will be defined inside our `style.css` file.

`src/style.css`
```javascript
.nav-active {
  color: grey;
  font-weight: bold;
}

```
And then, we make sure we import our CSS file into our `App.js`.(change the export default on all files). 

After that, inside our `App.js`, we create a string containing the class's name and write a conditional statement that adds the class name whenever it is active. This is possible due to the `isActive` boolean we are exposed to.

`src/App.js`
```javascript
import React from 'react';
import './style.css'
import { BrowserRouter, NavLink } from 'react-router-dom';

export default function App() {
  let activeClassName = "nav-active";
  return (
    <BrowserRouter>
      <header>
        <h1>Hello World</h1>
      </header>
      <nav>
        <NavLink to="" className={({ isActive }) => isActive ? activeClassName : undefined}>Home</NavLink>
        <NavLink to="about" className={({ isActive }) => isActive ? activeClassName : undefined}>About</NavLink>
        <NavLink to="contact" className={({ isActive }) => isActive ? activeClassName : undefined}>Contact</NavLink>
      </nav>
    </BrowserRouter>
  );
}
```

![Styles, applied](https://blog.openreplay.com/747b2235ffa79bea40f3477ab1ba6fee/image04.gif)

As we can see, the styles are applied to the links when clicked.

## Adding Pages to the Routes
Now, we will see how to create pages that correspond with the routes. For this, we need to create a folder called `pages` inside our `src` folder and create the following pages:

- `Home.js`
- `About.js`
- `Contact.js`
- `Error.js`

![Pages to be created](https://blog.openreplay.com/static/e6225a29f1cfbe5314144d22270c0580/23f0b/image05.png)

After Creating the pages, we will add some content to the pages.

`/src/pages/Home.js`
```javascript
import React from 'react';

function Home(){
  return (
    <div>
      <p>This is the Home Page</p>
    </div>
  )
}

export default Home;

```

`/src/pages/About.js`
```javascript
import React from 'react';

function About(){
  return (
    <div>
      <p>This is the About Page</p>
    </div>
  )
}

export default About;

```

`/src/pages/Contact.js`
```javascript
import React from 'react';

function Contact(){
  return (
    <div>
      <p>This is the Contact Page</p>
    </div>
  )
}

export default Contact;

```

`/src/pages/Error.js`

```javascript
import React from 'react';

function Error(){
  return (
    <div>
      <p>This is the Error Page</p>
    </div>
  )
}

export default Home;

```
The Error page was created so that routes that don't match any of the above-defined routes are assigned the Error Page.

Now, the next thing to do is make these routes show whenever we navigate a particular route.

First of all, we need to import a component from `react-router-dom` called `Routes`. The `Routes` component will contain all the different possible routes that can be displayed on that particular segment of a page, and it can be looked at as an array of Routes.

`/src/App.js`

```javascript
import React from 'react';
import './style.css'
import { BrowserRouter, NavLink, Routes } from 'react-router-dom';

export default function App() {
  let activeClassName = "nav-active";
  return (
    <BrowserRouter>
      <header>
        <h1>Hello World</h1>
      </header>
      <nav>
        <NavLink to="" className={({ isActive }) => isActive && activeClassName}>Home</NavLink>
        <NavLink to="about" className={({ isActive }) => isActive && activeClassName}>About</NavLink>
        <NavLink to="contact" className={({ isActive }) => isActive && activeClassName}>Contact</NavLink>
      </nav>
      <Routes>
        
      </Routes>
    </BrowserRouter>
  );
}

```

To define individual Routes that can be possibly displayed in the `Routes` component, we use another component called `Route`.

The `Route` component accepts two props.
- `path`: This is the path to which the page URL should navigate. This prop is similar to the `to` prop of the `NavLink` component.
- `element`: This contains the element that will be rendered when the page navigates to that route.

`/src/App.js`
```javascript
import React from 'react';
import './style.css'
import Home from './pages/Home'
import About from './pages/About'
import Contact from './pages/Contact'
import Error from './pages/Error'
import { BrowserRouter, NavLink, Routes, Route } from 'react-router-dom';

export default function App() {
  let activeClassName = "nav-active";
  return (
    <BrowserRouter>
      <header>
        <h1>Hello World</h1>
      </header>
      <nav>
        <NavLink to="" className={({ isActive }) => isActive && activeClassName}>Home</NavLink>
        <NavLink to="about" className={({ isActive }) => isActive && activeClassName}>About</NavLink>
        <NavLink to="contact" className={({ isActive }) => isActive && activeClassName}>Contact</NavLink>
      </nav>
      <Routes>
        <Route path="/" element={<Home/>} />
        <Route path="about" element={<About/>} />
        <Route path="contact" element={<Contact/>} />
        <Route path="*" element={<Error/>} />
      </Routes>
    </BrowserRouter>
  );
}

```

After creating the Routes, the nav links should lead to the pages they are designated to.

![Links, working](https://blog.openreplay.com/3107213b68b6c7378e69e9ae3a0e0635/image06.gif)

## Creating a Normal Link
The way to create regular links in `react-router-dom` is by using the `Link` component.

NOTE: `Link` component is very similar to the `NavLink` component. The only difference is that `NavLink` knows when it is active while `Link` does not.

We will import it into the component/page we want to use it.

For example, we will create a Link inside our Contact page that points to the home page.

`/src/pages/Contact.js`

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

function Contact(){
  return (
    <div>
      <p>This is the Contact page</p>
      <Link to="/">Back to Home</Link>
    </div>
  )
}

export default Contact;
```

![Link to home](https://blog.openreplay.com/f39a084d9040528c6bff6ccffcb5274b/image07.gif)

NOTE: To link to pages, use a "/", which shows that we are navigating to the base route. To navigate to other base route pages, we use a `/` and the name, e.g. `/contact`, `/about`, etc.



## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

_Start enjoying your debugging experience - [start using OpenReplay for free](https://github.com/openreplay/openreplay)._




## Redirecting to another Page
Suppose we created a `Dashboard` page that will redirect us to the home page when clicked. There are two ways to do this in `react-router-dom` v6.

- Using the `Navigate` component
- Using the `useNavigate` hook

### Using the `Navigate` component

The `Navigate` element changes the current location of the page whenever rendered. The way to use the `Navigate` element is to 
- import the `Navigate` component from `react-router-dom`.
- Add a `to` prop that points to the location the page is to redirect to.

Adding the `dashboard` to a nav link in `src/App.js`

```javascript
import React from 'react';
import './style.css'
import Home from './pages/Home'
import About from './pages/About'
import Contact from './pages/Contact'
import Error from './pages/Error'
import { BrowserRouter, NavLink, Routes, Route, Navigate } from 'react-router-dom';

export default function App() {
  let activeClassName = "nav-active";
  return (
    <BrowserRouter>
      <header>
        <h1>Hello World</h1>
      </header>
      <nav>
        <NavLink to="" className={({ isActive }) => isActive && activeClassName}>Home</NavLink>
        <NavLink to="about" className={({ isActive }) => isActive && activeClassName}>About</NavLink>
        <NavLink to="contact" className={({ isActive }) => isActive && activeClassName}>Contact</NavLink>
        <NavLink to="dashboard">Dashboard</NavLink>
      </nav>
      <Routes>
        <Route path="/" element={<Home/>} />
        <Route path="about" element={<About/>} />
        <Route path="contact" element={<Contact/>} />
        <Route path="dashboard" element={<Navigate to="/" />} />
        <Route path="*" element={<Error/>} />
      </Routes>
    </BrowserRouter>
  );
}

```

![Redirection](https://blog.openreplay.com/7b003e5d146114a45847c9c147cb7930/image08.gif)

And now, whenever we click on the dashboard link, it takes us back to the home page.

### Using the `useNavigate` hook

The `useNavigate` hook can also be used to redirect pages. Suppose we have a button on our About page that redirects us to the homepage. We will:
- import the `useNavigate` hook
- define a variable called `navigate` that calls the `useNavigate` function
- call the navigate function and give the path to be redirected to as a parameter

`/src/pages/About.js`
```javascript
import React from 'react';
import { useNavigate } from 'react-router-dom';

function About(){
  let navigate = useNavigate();
  return (
    <div>
      <p>This is the About Page</p>
      <button onClick={()=> navigate("/")}>Redirect</button>
    </div>
  )
}

export default About;
```

And we should have this:

![Redirection with the hook](https://blog.openreplay.com/839fa74748f45b304a86d0a770e1aec6/image09.gif)

##  Passing States with Router

While passing states in `react-router-dom`, there are three ways to achieve this:
- Using the `Link` component
- Using the `Navigate` component
- Using the `useNavigate` hook

### Using the `Link` component
We will pass data using the `Link` component from our `Contact` page to our `Home` page.

`/src/pages/Contact.js`
```javascript
import React from 'react';
import { Link } from 'react-router-dom';

function Contact(){
  return (
    <div>
      <p>This is the Contact page</p>
      {/* Pass in any Values you want to save in state, inside the state prop */}
      <Link to="/" state={"From Contact Page"}>Back to Home</Link>
    </div>
  )
}

export default Contact;
```

And now, to access the state, we use another hook called `useLocation` inside the page receiving the information (Home Page). This hook will expose us to the value inside the state variable.

`/src/pages/Home.js`

```javascript
import React from 'react';
import { useLocation } from 'react-router-dom'

function Home(){
  let location = useLocation();
  return (
    <div>
      <p>This is the Home Page</p>
      { location.state && <p>From Dashboard</p>}
    </div>
  )
}

export default Home;
```

![Links in a page](https://blog.openreplay.com/3ee90d3698ed15dfd2042ad9acbb11dc/image10.gif)

### Using the `Navigate` component
The `Navigate` component can also pass states in a `react-router-dom`. This is done by giving the `Component` state prop that contains the value we will want it to have. For example, our Dashboard redirects to our Home Page using the `Navigate` component. Now we will pass a state value into the `Navigate` component, which will get displayed on the `Home` page.

`/src/App.js`

```javascript
...

<Route path="dashboard" element={<Navigate to="/" state={"From Dashboard"}/>} />

...
```

`/src/pages/Home.js`
```javascript
import React from 'react';
import { useLocation } from 'react-router-dom'

function Home(){
  let location = useLocation();
  return (
    <div>
      <p>This is the Home Page</p>
      { location.state && <p>From Dashboard</p>}
    </div>
  )
}

export default Home;
```

![Using the navigate component](https://blog.openreplay.com/cb7c401834c89fe35a1c5c9b5be18a0a/image11.gif)

### Using the `useNavigate` hook
The function `navigate()`, which we called when learning how to redirect pages using the `useNavigate` hook, accepts two parameters: `to` and an object that contains a state. We will make the `Redirect` button carry a state to the home page.

`/src/pages/About.js`
```javascript
import React from 'react';
import { useNavigate } from 'react-router-dom';

function About(){
  let navigate = useNavigate();
  return (
    <div>
      <p>This is the About Page</p>
      <button onClick={()=> navigate("/", { state: "From the About Page"})}>Redirect</button>
    </div>
  )
}

export default About;
```

`/src/pages/Home.js`
```javascript
import React from 'react';
import { useLocation } from 'react-router-dom'

function Home(){
  let location = useLocation();
  return (
    <div>
      <p>This is the Home Page</p>
      { location.state && <p>From the About Page</p>}
    </div>
  )
}

export default Home;
```
![Using the useNavigate hook](https://blog.openreplay.com/9592bc37adca14551fb04d39f32cfc07/image12.gif)

## Protected Routes
Sometimes in our routing system, we might not want users to visit a particular page if they are not authenticated. We stop users from accessing these pages by protecting the routes. 

### Setting up a simple Auth System

In this part of the tutorial, we will bring in the `useState` hook, which will help us set a boolean login state.  This state will then determine if the user can be taken to the `dashboard` page, which is the route we would like to protect.

`/src/App.js`
```javascript
...
let [loggedIn, setLoggedIn] = useState(null);
function handleLogin(){
  setLoggedIn(true);
}
function handleLogout(){
    setloggedin(false);
}
...
<Route path="/" element={<Home login={handleLogin} />} />
...
```

Now, we have a function that logs a user in, and a function that logs a user out, and we have passed that function as a prop to the `Home` component. The next thing to do is create a login button on the home page.

`/src/pages/Home.js`
```javascript
import React from 'react';
import { useLocation } from 'react-router-dom';

function Home({ login }) {
  let location = useLocation();
  return (
    <div>
      <p>This is the Home Page</p>
      <button onClick={login}>Login</button>
      {/* {location.state && <p>From the About Page</p>} */}
    </div>
  );
}

export default Home;

```

![Basic auth](https://blog.openreplay.com/static/53452e7f4f6e557997fc8ddbd48cd03a/9cb1c/image13.png)


So, the user is automatically logged in whenever he clicks `Login`.

### Creating a Dashboard Page

This will be the page where the user will be redirected whenever logged in. We will create a new `/Dashboard.js` file inside the `pages` folder and then add the following code.

`/src/pages/Dashboard.js`

```javascript
import React from 'react';

function Dasboard({ logout}){
  return (
    <div>
      <p>Welcome User </p>
      <button onClick={logout}>Logout</button>

    </div>
  )
}

export default Dashboard;
```

### Protecting the Dashboard Page

To protect the `Dashboard` page, we will write a conditional statement on the route of the dashboard.

`/src/App.js`
```javascript
...
import Dashboard from './pages/Dashboard'
...
<Route 
    path="/" 
    element={
      loggedIn ? 
      <Navigate to="/dashboard"/> : 
      <Home login={handleLogin} />} 
/>
<Route
  path="dashboard"
  element={
    loggedIn ? 
    <Dashboard logout={handleLogout}/> : 
    <Navigate to="/" state="From Dashboard" />}
/>
```
This will prevent the user from accessing the route if the user is not logged in. But once the user is logged in, the route is now accessible. Finally, let us redirect to the dashboard whenever the user clicks the Logout button.

`/src/pages/Home.js`
```javascript
import React from 'react';
import { useNavigate } from 'react-router-dom';

function Home({ login }) {
  let navigate = useNavigate();
  return (
    <div>
      <p>This is the Home Page</p>
      <button onClick={()=>{
        login();
        navigate('/dashboard')
      }}>
        Login
      </button>
      {/* {location.state && <p>From the About Page</p>} */}
    </div>
  );
}

export default Home;

```

And now, we should have a fully working simple Auth system and protected Dashboard route.

![A fully working auth system](https://blog.openreplay.com/6c3a3172e6ca945d3434068aefd1fe86/image14.gif)

## Adding Nested Routes

We are going to create a `/dashboard/settings` route which means we will have the `settings` route inside the `dashboard` route.

`/src/App.js`
```javascript
...
<Route
  path="dashboard"
  element={
    loggedIn ? 
    <Dashboard logout={handleLogout}/> : 
    <Navigate to="/" state="From Dashboard" />}
>
  <Route path="settings" element={<p>This is the nested Settings route</p>}/>
</Route>
...
```
The nested `Route` component creates a `/settings` inside `/dashboard`. But for this to work, we must import the `Outlet` component into our `Dashboard.js`.

`/src/pages/Dashboard.js`
```javascript
import React from 'react';
import { Outlet, Link } from 'react-router-dom';

function Dasboard({ logout }){
  return (
    <div>
      <p>Welcome User </p>
      <Link to="settings">Settings</Link>
      <Outlet/>
      <button onClick={logout}>Logout</button>
    </div>
  )
}

export default Dashboard;
```

![Nested routes](https://blog.openreplay.com/31484150a588301fe0fefa9ffaedb352/image15.gif)

### Using `useParams`

`useParams` is a `react-router-dom` hook with access to a URL parameter value. We will create a `Profile.js` page that will grab whatever `id` we give the URL and display it on the page.

`/src/pages/Profile.js`

```javascript
import React from 'react';
import { useParams } from 'react-router-dom';

function Profile(){
  let { userId } = useParams();
  return (
    <div>
      <p>The id of this user is { userId }</p>
    </div>
  )
}

export default Profile;
```

`/src/App.js`

```javascript

import Profile from './pages/Profile'
...
<Route path="profile">
  <Route path=":userId" element={<Profile/>}/>
</Route>
```

And now, whenever we navigate to `/profile/1` (Note: The id can be any value), we have this displayed:

![Route with parameters](https://blog.openreplay.com/static/38953610e260e2c2c2a9c2ee920a233d/5ad18/image16.png)

## Conclusion

`react-router-dom` v6 is a library with many features, and we have gone over the basics of how the library works. We have learned
- Creating navigation links
- Adding pages to routes
- Creating normal links
- Redirecting pages
- Protecting routes
and a lot more!

With this, you should comfortably know how to use the `react-router-dom` library version 6.

The source code of all the operations performed in this tutorial can be found here on Stackblitz.
https://stackblitz.com/edit/react-kunxgu

## References
- Official React Router Documentation: https://reactrouter.com/


[![newsletter](https://blog.openreplay.com/static/e6b18eda7a327511296a2f27692f9c70/e9957/newsletter.png)](https://newsletter.openreplay.com/)