This is the first article from a new series dedicated to the most popular library, that handles routing in React applications. Namely, the article will discuss the latest version of React Router. To give you an idea of the extent of the changes in this library, I will show you how the size of the “react-router-dom” bundle has changed. I have selected the most popular version according to the current number of downloads. It is version 5.3.4, which is likely to be installed by most of you on your projects.
As you can see, the size in the super compressed form is 9.8 Kb. The graph on the right side of the picture shows versions 6.0, 6.1, 6.2, and 6.3, and the length of the column shows that the size of the bundle has almost halved. If translated into numbers, version 6.3 takes only 5.9 Kb, which is almost 46% smaller than the fifth version of the router.
The refactoring seems to have been a success. The team did an excellent job but the React Router, as you can see, did not rest on its laurels and decided to make an incredible change again.
Namely, they released version 6.4 and thus increased the size by almost three times compared to version 6.3. As a result, the size of the bundle of version 6.4 is 17.5 Kb and keeps increasing, which is already 78% more than the fifth version of the router.
As you can see, the codebase has changed a lot. It is impossible to analyze everything within a single article. Therefore, a whole series of articles is planned, in which I will try to explain what exactly has changed and how we can now work with this new version of the Router.
V5 initialization
Let’s start with the basic initialization of the Router. It has changed a lot visually, so let us quickly study how it all works. Here is the initialization of the application on the fifth version of the Router:
const App = () => {
return (
<BrowserRouter>
<Switch>
<Route path="/about">
<About/>
</Route>
<Route path="/users">
<Users/>
</Route>
<Route path="/">
<Home/>
</Route>
</Switch>
</BrowserRouter>
)
}
We already have here <BrowserRouter> which is familiar to us and it encloses the entire application. We will see the <Switch> component in absolutely all applications and, of course, the <Route> themselves, as we know, nothing will work without them. Most of you must know what idea lies behind the <Switch> component – it renders the first child <Route> or <Redirect> that matches the current location. Since you are already familiar with this, I will not dwell on it for a long time.
V6.4 initialization
Now, let’s see how it looks on the react-router-dom version 6.4. The first thing that should catch your eye is createBrowserRouter, which is a function, not a JSX component. It takes the entire routing as an array of objects describing the routes, and the result of the createBrowserRouter function is then inserted into the <RouterProvider />.
const router = createBrowserRouter([
{
path: "/",
element: <Home/>
},
{
path: "/about",
element: <About/>
},
{
path: "/users",
element: <Users/>
}
]);
const App = () => {
return <RouterProvider router={router} />;
}
This is quite an impressive change and, it seems to me, quite a demanded one. I have repeatedly seen projects reinvent the wheel to describe routes in the form of JS config and this required writing a layer that could convert this config into the correct JSX code.
Describe routing in the old format
Those who do not quite like this approach also have the option of describing it all in the old format. First, there is the same createBrowserRouter function already familiar to you, and a new createRoutesFromElements function inserted inside, imported from the router itself. In the end, we can describe the routes as before. This feature can be probably perceived as partial backward compatibility which, of course, will simplify the migration of many projects to a new router.
import {
createBrowserRouter,
createRoutesFromElements,
Route,
RouterProvider,
} from "react-router-dom";
const router = createBrowserRouter(
createRoutesFromElements(
<>
<Route path="/about" element={<About/>} />
<Route path="/users" element={<Users/>} />
<Route path="/" element={<Home/>} />
</>
)
);
Switch is gone
As you can see, our Switch component has disappeared. After a couple of experiments, I realized that the ideology of choosing the right route has now changed. How does it work exactly? So far, it is hard to say. Initial experiments showed the following results: if the path matches the route exactly, then the corresponding element is displayed. With this option, everything is simple and predictable.
404 Not Found
What happens if we enter an url in the browser that is not described in the router? In this case, we will see the following screen:
We can see an error 404 “Not found” and a hint below saying that we should use the errorElement property to render the error screen. It is an extremely amusing behavior. Although a component with that text does not exist in our project, as it is a component of the React Router itself. It is a very interesting approach. You get an additional component in the bundle, but this is not very important. Let’s better understand how to replace this screen with your own.
const router = createBrowserRouter([
{
path: "/",
element: <Home/>,
errorElement: <div>Not Found</div>
},
{
path: "/about",
element: <About/>
},
{
path: "/users",
element: <Users/>
}
]);
The errorElement property appeared and its value replaced what we saw earlier. It is interesting as it only worked in the case when the error element was added specifically to the “home” route. In other cases, it did not work no matter what route I entered. So, this is the way to make a 404 page and it seems to me that it has become a little more obvious than what we had using <Switch>.
Comparing Route Properties
The errorElement is a new property that we have been introduced to. I wonder what other properties have appeared? I did not find well described properties in the documentation, so I decided that the best documentation is, as always, the source code. I wrote out all the properties that I found in the route component for version 5.3.4 and for version 6.4.
I warn you in advance that the types are written in approximation, since in the fifth version the code is not written in a TypeScript.
In the sixth version, there are many branches of the types, so these are only approximate types.
What do we see here? Version 5 has the first property children; version 6 has no changes in this property. Then in the fifth version, we see two properties about the same thing: component and render. They are both replaced with element property. The next property is path and it remained the same, except now you cannot pass an array of strings to it. Then, the sensitive property was renamed into caseSensitive. It is not difficult. The exact and strict properties have disappeared altogether, since the ideology of router mapping has now changed and they, apparently, have become completely irrelevant. You can no longer pass location to route.
Only the new properties of the sixth version remained, let’s go through them briefly. We have already encountered errorElement, but this was only the first occurrence. As far as I understand, you can do even more interesting things with it, but I will leave that for other articles.
As far as I understand, the hasErrorBoudary field determines whether the error should pop up further, however, I have found nothing about it in the documentation yet. I still need to give it time. The next id property is generated automatically but you can also pass it. Frankly, I do not really understand why we might need it but time will show.
The next internal property is the index used to mark the route as root or nested. They change a lot depending on it. Even the types for root and nested are slightly different. Then the famous trio is loader, shouldRevalidate, and action. These are the main new features introduced in this version, which completely changed my perception of this library. However, I am not sure yet, whether it changed in a good direction, but it will be explored in other articles.
The last property is the handle. I did not understand at once its point but it seems like it is a field through which any value, any data type, anything can be passed to the component. As far as I understood, with the new features of the Router, it will be very useful.
Summary
It is worth mentioning that I have not yet used this version of the Router on a real project, I am just getting to know it. Therefore, if you already have practical experience or you can test what was discussed in this article on a real project, I will be very grateful for your comment. I will try to read all the comments and respond to them. Additionally, if you would like to learn more about the new version of React Router, please let me know, so that I can understand whether this type of analysis is relevant to you.
Useful post.
Guide for beginners..
React developers are software developers who specialize in building web applications and user interfaces using the React JavaScript library. React, also known as React.js or ReactJS, is an open-source library developed by Facebook that allows developers to create dynamic and interactive user interfaces efficiently.