A look at React Router 6
The release of React router version 6 is just around the corner. I thought it was time to take a good look at it …
Installing
To use React Router, we need to install the react-router-dom
and history
packages.
npm install history react-router-dom@next
Note that react-router-dom
is still in beta, so we’ve explicitly defined the next
version.
Setting up top-level routes
A route represents a page in an app. We define all the routes using a number of elements in JSX from React Router:
<BrowserRouter>
<Routes>
<Route path="" element={<HomePage />} />
<Route
path="customers"
element={<CustomersPage />}
/>
<Route
path="products"
element={<ProductsPage />}
/>
<Route
path="products/:id"
element={<ProductsPage />}
/>
</Routes>
</BrowserRouter>
The BrowserRouter
element is usually the topmost element in the component tree because all other React Router elements need to be nested within it. BrowserRouter
provides information about the current location to its descendants and will perform navigation between pages.
A set of routes is defined as a Routes
element. Each route is defined in a Route
element within it. Whenever the location changes, Routes
finds the child Route
element that best matches the path
prop to the current location and renders the element defined in the element
prop. So, the Route
element is a bit like an if
statement - if its path matches the current path, it renders its element.
Routes
replaces Switch
in previous versions of React Router and a key difference is that the ordering of the Route
elements within it don’t impact the matching like it used to do with Switch
. The matching in Routes
is much smarter with precedence based on how specific a the path
is with a Route
.
Navigation
Links
A Link
element will navigate to the route specified in the to
prop when clicked.
<Link to="buy">Buy</Link>
to
is a relative path to the route that rendered it if the path doesn’t start with a /
. If the path begins with a /
, it is relative to the root of the app.
Link
is an a
element under the hood but doesn’t cause server-side navigation - the navigation happens all in the browser.
There is another element that we can use for linking called NavLink
. Unlike Link
, NavLink
knows whether or not it is active:
<nav>
<NavLink to="/" activeClassName="active" end>
Home
</NavLink>
<NavLink
to="customers"
activeClassName="active"
>
Customers
</NavLink>
<NavLink
to="products"
activeClassName="active"
>
Products
</NavLink>
</nav>
An activeClassName
or activeStyle
prop can be used to style the underlying a
element when its route is active.
The end
prop means that NavLink
will only become active if the current path is a full match. In the example above, without end
, Home will always be active.
Programmatic navigation
Programmatic navigation can be achieved with the useNavigate
hook. The hook returns a function that will invoke navigation with the path passed into it:
const navigate = useNavigate();
A common use case is a form submission:
<form
onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(
e.currentTarget
);
// submit form
navigate("/success");
}}
>
<input
name="name"
type="text"
placeholder="name"
/>
<button type="submit">Save</button>
</form>
The useNavigate
hook is new in version 6 and is suspense ready.
Not found routes
A not found route can be defined when no other route matches the current path:
<Route path="/*" element={<NotFoundPage />} />
Path /*
is used because it has the weakest precedence, which means the router will only pick it up if no other routes match.
Route parameters
Parameters can be added to a path after a colon:
<Route
path="products/:id"
element={<ProductPage />}
/>
The useParams
hook can then be used to retrieve a parameter value from the path:
const { id } = useParams();
const product = products.find(
(p) => p.id === id
);
Descendant routes
You can have more than one set of routes with the Routes
element. Further down the component tree, within the top-level Routes
element, we can have an additional Routes
element:
<Routes>
<Route
path="buy"
element={
<p>Thank you for buying this product!</p>
}
/>
<Route
path="*"
element={
<Link to="buy" className="link">
Buy
</Link>
}
/>
</Routes>
This is within ProductPage
within the following route:
<Route
path="products/:id*"
element={<ProductPage />}
/>
The 2nd level routes result in a Buy button initially being rendered. When this is clicked, it is replaced with the message, Thank you for buying this product!.
Nice!
Nested layout
Route
elements can be nested inside one another:
<Route
path="products"
element={<ProductsPage />}
>
<Route path=":id*" element={<ProductPage />} />
</Route>
In the above example, ProductsPage
will be rendered for the products
path. Both ProductsPage
and ProductPage
will be rendered when the path is products/:id.
. An Outlet
element is used to specify where ProductPage
is rendered within ProductsPage
.
<div className="product-list">
{filteredProducts.map(({ id, name }) => (
<Link key={id} to={`/products/${id}`}>
{name}
</Link>
))}
</div>
<Outlet />
This approach can produce nested layouts where the surrounding UI remains consistent while the inner content changes between routes.
Search parameters
The useSearchParams
is used to read and update search parameters. It returns an array of two values: the current location’s search params and a function to update them:
let [
searchParams,
setSearchParams,
] = useSearchParams();
searchParams
is a set utility methods allow specific search parameters to be retrieved.
setSearchParams
can be used to update the search parameters:
<form
onSubmit={(e) => {
e.preventDefault();
setSearchParams(
`search=${new FormData(
e.currentTarget
).get("search")}`
);
}}
>
<input
name="search"
type="search"
placeholder="search ..."
/>
</form>
A working example of these features is available in CodeSandbox at https://codesandbox.io/s/react-router-6-0y5qc?file=/src/App.tsx.
Wrap up
The new Routes
component in version 6 is a great addition to React Router. Its relative matching makes code a little cleaner. The ability to do nested layouts with nested Route
elements and Outlet
is a nice touch. Well worth checking out!
Did you find this post useful?
Let me know by sharing it on Twitter.If you to learn about using TypeScript with React, you may find my course useful: