Nested routes in React are not as complex as you might think, especially, with React Router V5. Routes are nothing but React components. Therefore, just like any other component, they render anywhere in a React application including in child components.
Note: If you are new to React Router, please read this post before you processed.
React Router uses hooks in Nesting routes
1.) useParams
2.) useRouteMatch
We will discuss these hooks later in the post. First, let’s look at the structure of the App.
Table of Contents
Structure of the App
Consider the Following Components structure
App has three two child components: Home and Courses.
The Courses component has a child component called Subject.
When a user clicks on the Courses link, it should render the Subject component.
URL path for each component
COMPONENT | URL PATH |
---|---|
HOME | / |
COURSES | /courses |
SUBJECT | /courses/:subject |
When a user clicks on courses, the URL path change to /courses and displays all the subjects.
After that, if the user clicks on a subject, it displays the name of the subject at the URL path /courses/:subject.
“: subject” is a URL parameter, thus, it is dynamically assigned a value as the user clicks on the name of the subject.
Parent Component(App.js)
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/courses">Courses</Link>
</li>
</ul>
</nav>
<Switch>
<Route path="/courses">
<Courses />
</Route>
<Route exact path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
Passing path information from <Courses> to <Subject>
There are two important things to understand in nesting Routes
1.) Once you create <Router> in the parent component, you can use <Route> in the parent component as well as in child components
2.) The components in <Route> will render as long as the path prop is matched with the URL path
Courses component(Courses.js)
import React from 'react'
import { useRouteMatch } from 'react-router';
import {
Switch,
Route,
Link
} from "react-router-dom";
import Subject from './Subject';
export default function Courses() {
const { path, url } = useRouteMatch();
return (
<div>
<h3>Select the subject</h3>
<ul>
<li>
<Link to={`${url}/javascript`}>Javascript</Link>
</li>
<li>
<Link to={`${url}/react`}>React</Link>
</li>
<li>
<Link to={`${url}/typescript`}>Typecscript</Link>
</li>
</ul>
<Switch>
<Route path={`${path}/:subject`}>
<Subject />
</Route>
</Switch>
</div>
);
}
There are some important lines of codes to understand in the above code. let’s look at them
useRouteMatch Hook
In the earlier versions of React Router(and also in the latest versions), there are three methods to render routes.
If you use these methods, the following objects will be passed to the rendering child component as props
- match
- location
- history
For example, the following code snippet uses <Route component> to render a child component matching a URL path. if the URL path matches with prop path=”/courses/subject”, the Subject component will render and match, location, and history objects will pass as props to the Subject component.
<Route path="/course/subject" component={Subject} />
With the introduction of React Router V5, things have changed. the new way to render Route is as follows
For example:
<Route path="/course/subject">
<Subject />
</Route>
However, when you render a route like this, the child component (Subject) does not receive props (match, location, history) from the parent component. So, how does the React Router V5 deal with this issue?
The answer is a new hook called useRouteMatch. Using this hook, we can utilize the match object.
match object has four properties: isExact, params, path, url.
What we need here in our App for nested Route are path and url properties.
As you can notice in the above code in the Course component, the url property is used in the <Link > component since the url property contained the full URL . The path property is used in the <Route> component because the path contains url with url parameters(if exists).
for example, if you pass match object to the Subject component, and if a user click on javascript( which is a Link ),
url would be /courses/javascript
path would be /courses/:subject
Note: However, in our application, We DO NOT pass match object from Course to Subject component.
Dynamic paths
<Route path={`${path}/:subject`}>
<Subject />
</Route>
As you can see in the above code, we have a dynamic path instead of a static path( ex: /courses/:subject)
The main advantage of using dynamic paths is that it ensures that paths are not broken if someone changes the /courses part of the path in the parent component(App.js)
App.js
<Route path="/courses">
<Courses />
</Route>
The path, /course/:subject , creates params object for each value of URL parameter when you click on the link
{ subject: ‘javascript’ }
{ subject: ‘react’ }
{ subject: ‘typescript’ }
You can use the useParams hook inside the Subject component to access the value( using the key ) of the params object.
Subject component(Subject.js)
import { useParams } from 'react-router';
export default function Subject(){
const { subject } = useParams();
return (
<>
<h3>{ subject }</h3>
</>
);
}
Conclusion
React Router V5 provides a simplified way to create nested routes dynamically when compared to their previous versions. It uses two hooks, useRouteMatch, and use params to create dynamic nested routes. This way react-router v5 keeps the consistency with react’s component-based architecture.