Go to main content
August 17, 2021
Cover image

react-router version 6 is currently in beta. I guess it will be released soon. So, what a great time to explore this library which is one of the most used routing library for React.

In this series of article, we are going to briefly see the changes compared to the previous version, how to use it and then we will write the specifications and code our own implementation the same way react-router is implemented, it will just an idea of how it’s really implemented, it won’t have all the feature, but after reading all the article you will be able to explore it on your own on the repository.

Let’s get it started.

The Route component has a new API which is a lot simpler. The props available are:

  • path (default value ”/“)
  • element which is the element to display. No more render or component
  • caseSensitive instead of sensitive to tell that the path needs to match with the same case. Default value to false.

In version 5:

<Route path="/" component={HomePage} />

// or

<Route path="/">
  <HomePage />
</Route>

In version 6:

<Route path="/" element={<HomePage />} />

You can nest Route together. For example:

<Route path="hobby" element={<HobbyLayout />}>
  <Route
    path="favorite"
    element={<FavoriteHobbyListBody />}
  />
  <Route path=":name" element={<HobbyDetailBody />} />
</Route>;

// with

function HobbyLayout() {
  return (
    <>
      <h1>Hobby layout page</h1>
      {
        // Will display the right nested Route
      }
      <Outlet />
    </>
  );
}

The version 6 introduces a new component name Routes which is kindly the equivalent to the Switch component which is no more present.

And it’s also possible to nest Routes

In version 5:

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="hobby" component={HobbyPage} />
      </Switch>
    </BrowserRouter>
  );
}

function HobbyPage() {
  const match = useRouteMatch();

  return (
    <Switch>
      <Route path={`${match.path}/favorite`}>
        <FavoriteHobbyListBody />
      </Route>
      <Route path={`${match.path}/:name`}>
        <HobbyDetailBody />
      </Route>
    </Switch>
  );
}

In version 6 it becomes:

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="hobby/*" element={<HobbyPage />} />
      </Routes>
    </BrowserRouter>
  );
}

function HobbyPage() {
  return (
    <Routes>
      <Route
        path="favorite"
        element={<FavoriteHobbyListBody />}
      />
      <Route path=":name" element={<HobbyDetailBody />} />
    </Routes>
  );
}

It’s time to see relative path.

As you can see in the example above, for the routes path you don’t have to take care about the match.url anymore. All path are relatives now, unless you specify it’s an absolute path by starting your path with a slash, for example:

// If I am in the `Route` element with the path
// `/hobby`


// Will navigate to `/hobby/favorite`
<Link to="favorite">Favorite hobby link</Link>

// Will navigate to `/about`
<Link to="/about">About page link</Link>


// Route for path `/hobby/favorite`
<Route
  path="favorite"
  element={<FavoriteHobbyListBody />}
/>

// Watch out it is also route for `/hobby/favorite`
<Route
  path="/favorite"
  element={<FavoriteHobbyListBody />}
/>

This is a cool feature, you don’t have to care anymore of the sorting of your Route elements inside the Routes.

react-router will do a smart sorting, you don’t have to be afraid that the first Route defines “blocks” all next ones.

For example in version 5:

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/">
          <HomePage />
        </Route>
        <Route path="/hobby">
          <HobbyPage />
        </Route>
      </Switch>
    </BrowserRouter>
  );
}

function HomePage() {
  return <p>Home page</p>;
}

function HobbyPage() {
  return <p>Hobby page</p>;
}

Even on the url /hobby, you will see the content of HomePage.

Not the case anymore in version 6 with the code below:

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/hobby" element={<HobbyPage />} />
      </Routes>
    </BrowserRouter>
  );
}

function HomePage() {
  return <p>Home page</p>;
}

function HobbyPage() {
  return <p>Hobby page</p>;
}

I only have listed the more important changes, but there are more. If you want read a well written, with all changes listed, you can read the migration guide to v6 .


Before doing some code, let’s describe the specifications:

  • a Routes can only return ONE matching Route
  • we want to be able to nest Route together. For example:
<Route path="hobby" element={<HobbyPageLayout />}>
  <Route path="/" element={<HobbyListBody />} />
  <Route path="favorite" element={<FavoriteHobbyBody />} />
</Route>

In this case the matching nested Route will be accessible by a component named Outlet. For example, for the HobbyPageLayout above :

function HobbyPageLayout() {
  return (
    <>
      <p>Hobby page layout</p>
      {
        // Will be basically HobbyListBody,
        // FavoriteHobbyBody or undefined
      }
      <Outlet />
    </>
  );
}
  • we want to be able to define path variable and be able to access it through useParams hook. For example:
<Route path="hobby/:name" element={<HobbyDetailPage />} />;

const { name } = useParams();
  • we want to be able to do nested Routes. But we do not want the API to be hard. In the nested we do not want to repeat the parent pathname (or using match.path). For example:
<Routes>
  <Route path="hobby/*" element={<HobbyPage />} />
</Routes>;

function HobbyPage() {
  return (
    <Routes>
      <Route path="/" element={<HobbyListBody />} />
      <Route
        path="favorite"
        element={<FavoriteHobbyBody />}
      />
      <Route path=":name" element={<HobbyDetailPage />} />
    </Routes>
  );
}
  • we do not want to care about slash while doing nested routes

  • we want to have relative path during navigation and be able to do absolute with leading ”/” to our path.

  • have hooks to defines routes :D

Now in the next article we are going to start the implementation, starting small:

  • no nesting Route and Routes
  • no path params
  • no relative path

Here is a little code sandbox of react-router v6:


We have seen the new react-router v6 API, that I find simpler and clearer. Relative link are really cool, nor more question to ask ourself like “Do I need a leading/trailing slash for my path?”, and will remove a lot of boilerplate code with match.url and match.path.

Specifications are ready for our in coming implementations and explorations.

For the next article , you will need to know the location and history API, you can read my article . And be sure, to be comfortable with React context, spoiler alert: there are quite a lot.


You can find me on Twitter if you want to comment this post or just contact me. Feel free to buy me a coffee if you like the content and encourage me.