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.
Difference between v5 and v6
New Route
API
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 morerender
orcomponent
-
caseSensitive
instead ofsensitive
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 />
</>
);
}
Note: As you can see the above example, it's still possible to define path with path params (ex
:name
).
Welcome to Routes
component
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>
);
}
Note: You may have noticed the trailing
/*
to parentRoute
which is important to tell "match deeply".
Perfect example to go to the next part about relative path.
Relative Routes and Links
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 />}
/>
Routes element are sorted by react-router
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>;
}
More changes
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.
Specifications for our implementation
Before doing some code, let's describe the specifications:
- a
Routes
can only return ONE matchingRoute
- 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();
Note: Of course, we want to be able to combine nested
Route
with path variable.
- 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 usingmatch.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
Note: You have probably noticed the
*
to tell match all.
Now in the next article we are going to start the implementation, starting small:
- no nesting
Route
andRoutes
- no path params
- no relative path
Playground
Here is a little code sandbox of react-router
v6:
Conclusion
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.
Want to see more ? Follow me on Twitter or go to my Website. 🐼
Top comments (0)