Mastering Nested Routes for Robust Web Applications (Using React Router V6)

Written by sojinsamuel | Published 2023/07/05
Tech Story Tags: react-router | react-router-v6 | react-tutorial | react-hooks | javascript | programming | web-development | reactjs-development

TLDRIn this article, we'll explore the fundamental concepts, delve into React Router v6, and learn about the powerful `useOutletContext` feature. By the end, you'll have a solid grasp of nested routes and how they can take your React applications to the next level.via the TL;DR App

I'm thrilled to have you here today because we're about to embark on an exciting adventure into the captivating world of React Router nested routes. Trust me, I've been in your shoes, and understanding nested routes can be quite a puzzle. But fear not, because I'll be your friendly guide, leading you through this journey step by step.

By the end of this article, you'll have a solid grasp of nested routes and how they can take your React applications to the next level. We'll explore the fundamental concepts, delve into React Router v6, and even learn about the powerful useOutletContext feature.

So, buckle up and get ready for an enlightening exploration of React Router nested routes!

Table of Contents:

  1. What are nested routes?
  2. React Router nested routes.
  3. Exploring useOutletContext

Are you excited? I sure am 😀 Let's dive right in and unravel the wonders of nested routes in React together!

What are nested routes?

In some websites, it's quite common to visit the about page by going to /about. When you land there, you'll see a cool cover image and the title About. And guess what? You'll have the option to choose one of two sub-pages:

  • About us, which can be found at /about/us/
  • About the Team, located at /about/team/

Isn't it great? You can explore more about the website and its awesome team through these sub-pages!

The About us page will display the same content as the /about page, but it will also include an additional section called About us below. Similarly, the About the Team page will show the same content as the /about page, but it will have an extra section called About the Team below.

This demonstrates nested routes, as the /about/us page combines two routes into one. It includes the content from both the /about route and the /about/us route.

React Router nested routes

To make nested routes work in React Router, follow these three steps:

  1. Start by nesting new <Route /> definitions inside an existing <Route /> element.
  2. Import and use an <Outlet /> component inside the route that will have nested routes.
  3. Ensure you have links pointing to these routes so you can view and test them.

Let's begin with an example where we have an <About /> component that renders on the /about path.

import {BrowserRouter, Routes, Route} from "react-router-dom";

function About() {
  return <>
        <h1>About</h1>

    </>;
}

function App() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path="/about/" element={<About />}>
                </Route>
            </Routes>
        </BrowserRouter>
    );
}

We aim to enhance the functionality of the <About /> component by enabling it to render nested routes. Essentially, whenever the path begins with /about, we want the component to render along with its corresponding child components. This way, we can consistently display the <h1>About</h1> heading on sub-pages like /about/us and /about/team.

Step 1: Let's start by defining nested <Route /> definitions

First, let's define the two nested routes under /about. We'll create a <Route path="us" /> and a <Route path="team" />. Remember, the paths are relative because we're nesting them inside <Route path="/about/" />. These two <Route /> components will be children of the <Route path="/about" />. So, the structure will look like this:

<Route path="/about/" element={<About />}>
    {/* about/us */}
    <Route path="us" element={<h2>About us</h2>}>
    </Route>
    {/* about/team */}
    <Route path="team" element={<h2>About the Team</h2>}>
    </Route>
</Route>

I've added some comments to help you out. So, when you have the path attribute set to us nested inside the path attribute set to /about/, it creates a final path for that route as /about/us. Similarly, if you have the path attribute set to team, it will become /about/team.

Start the nested routes without using a / character. Otherwise, you'll need to repeat the /about path. So, valid paths are us and /about/us. However, I recommend the first approach.

2. Use an <Outlet />

To make sure the nested routes are displayed, we'll need to tell the <About /> component how to render them. First, import the Outlet component from react-router-dom and use it within the <About /> component. This will determine the specific location in the JSX where the nested routes will be shown.

import {BrowserRouter, Routes, Route, Outlet} from "react-router-dom";

function About() {
  return <>
        <h1>About</h1>

        {/* Render nested routes for /about/... here */}
        <Outlet />
    </>;
}

function App() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path="/about/" element={<About />}>
                    {/* about/us */}
                    <Route path="us" element={<h2>About us</h2>}>
                    </Route>
                    {/* about/team */}
                    <Route path="team" element={<h2>About the Team</h2>}>
                </Route>
            </Route>
          </Routes>
        </BrowserRouter>
    );
}

If you put the <Outlet /> before the <h1>About</h1>, then the content of the nested routes like <h2>About us</h2> or <h2>About the Team</h2> will be displayed before the <h1>.

3. Add <Link /> elements

Finally, let's add the <Link /> elements so that we can easily view and test these nested routes.

import {BrowserRouter, Routes, Route, Outlet, Link} from "react-router-dom";

function About() {
  return <>
      {/* Content always rendered when the URL starts with /about */}
      <h1>About</h1>
      <Link to="us">About us</Link> | 
      <Link to="team">About the team</Link>

      <Outlet />
    </>;
}

function App() {
    return (
        <BrowserRouter>
          <Routes>
            <Route path="/about/" element={<About />}>
                {/* about/us */}
                <Route path="us" element={<h2>About us</h2>}>
                </Route>
                {/* about/team */}
                <Route path="team" element={<h2>About the Team</h2>}>
                </Route>
            </Route>
            </Route>
          </Routes>
        </BrowserRouter>
    );
}

useOutletContext

Sometimes, we need to pass data to the components that are rendered by the Outlet. For now, let's consider a basic example where we have a variable called data that we want to make accessible to any component rendered under the <Outlet />.

Instead of this basic example, If you want me to write a project based article, on how to do this let me know in the comments.

function About() {
    // we want to make this available to the <Outlet /> sub-components
    const data = {
        someValue: 123
    };

    return <>
        {/* Content always rendered when the URL starts with /about */}
        <h1>About</h1>
        <Link to="us">About us</Link> | 
        <Link to="team">About the team</Link>

        <Outlet />
    </>;
}

To achieve that, you can utilize the context attribute on the <Outlet /> component, which will automatically generate a context for you. This is a commonly used feature, and the React Router team has incorporated it directly into the library.

function About() {
    // we want to make this available to the <Outlet /> sub-components
    const data = {
        someValue: 123
    };

    return <>
        {/* Content always rendered when the URL starts with /about */}
        <h1>About</h1>
        <Link to="us">About us</Link> | 
        <Link to="team">About the team</Link>

        // pass it to Outlet as a context
        <Outlet context={data} />
    </>;
}

This special context attribute is exclusive to the <Outlet /> component. It automatically creates a context for us, which can be accessed by the children of <Outlet />. All we need to do is use it.

useOutletContext hook

The useOutletContext hook is a handy tool that helps us in various components that need to be rendered under the <Outlet />. Let's take the AboutUs component as an example.

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

function AboutUs() {
    const context = useOutletContext();
    console.log(context); // {someValue: 123}
    console.log(context.someValue); // 123

    // ...
}

You Nailed it Hacker 🥳

Congratulations on completing this captivating journey into the world of nested routes. I encourage you to apply what you've learned and experiment with nested routes in your own projects. Thank you for joining me on this enlightening exploration of nested routes in react. Happy coding, and may your React applications flourish with enhanced navigation and seamless user journeys!


Written by sojinsamuel | I am a junior React developer with a passion for building intuitive and engaging web applications.
Published by HackerNoon on 2023/07/05