React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.
To build single-page apps, we have to have some way to map URLs to the React component to display.
In this article, we’ll look at how to define nested routes with React Router.
Nested Routes
To define nested routes, first, we define a grandchild route to display the content of the nested routes. We can use the useParams
hook to get any route parameters.
Then we can define nested routes by defining a child component to hold our nested routes.
In the child component, we get the url
and path
properties from the useRouteMatch
hook.
Then we use the url
variable to prefix the path in the to
prop of the Link
s. In the Route
components, we prefix the path
prop with the path
property returned from useRouteMatch
.
Then we create a parent component that holds the child route that we defined above.
For example, we can define them as follows:
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams,
useRouteMatch
} from "react-router-dom";
function Topic() {
let { topicId } = useParams(); return (
<div>
<h3>{topicId}</h3>
</div>
);
}
function Topics() {
let { path, url } = useRouteMatch(); return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${url}/foo`}>Foo</Link>
</li>
<li>
<Link to={`${url}/bar`}>Bar</Link>
</li>
<li>
<Link to={`${url}/baz`}>Baz</Link>
</li>
</ul> <Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`}>
<Topic />
</Route>
</Switch>
</div>
);
}
function App() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul> <hr /> <Switch>
<Route exact path="/">
<p>Home</p>
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
);
}const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
On the top of the code above, we have the Topics
component to display the content of the nested route. We get the id
URL parameter with useParams
.
The Route
that renders Topic
has the path of /topics/:topicId
. :topicId
indicates a placeholder that we can get from useParams
.
Then we have the Topics
component, which is the parent of the Topic
component. It has the child routes as defined in the following code:
<Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`}>
<Topic />
</Route>
</Switch>
In the Route
we nest Topic
in it so we display whatever’s returned there.
The path
is set to path={`${path}/:topicId`}
so that we call useRouteMatch
to prefix the path with what we’ll define in App
. That means path
will be set to /topics
as we’ll do later.
We also have the Link
component’s to
props prefixed with the url
so that they’ll go to the right URL when we click on the links.
Then in App
, we have:
<Switch>
<Route exact path="/">
<p>Home</p>
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
to set the top-level routes. As we mentioned before, we’ll set the top-level route to topics
as we did in the second Route
component.
In the Link
components, we set the relative paths to go to when we click on them.
Then we get something like the following when we click on the links:
Conclusion
To define nested routes, we have to nest Route
objects within each other.
The cleanest way to do this is to split each level of nesting into their own components.
We can use the useRouteMatch
hook to return the path
, and url
. The path
is for prefix the path
prop of Route
s, and url
is for prefixing the to
prop of Links
of nested routes.