Learn

Up to this point, we’ve been working with routers that are relatively small. As our application grows and we add more features, we may want additional components to render within our defined views depending on user actions.

For example, suppose that we have an About page that will be rendered if we hit the path /about. We’d like to implement a new feature that will display a secret message in About if the path changes to /about/secret. We might try and do this:

/* imports ... */ const router = createBrowserRouter(createRoutesFromElement([ <Route path='/about' element={ <About/> }> />, <Route path='/about/secret' element={ <Secret/> }> /> ]));

Since React Router matches paths exactly, if we go to the path /about/secret, it will only render Secret and not About. We’d like to render About when we hit /about and also render Secret below About when we hit /about/secret. We can do this using nested routes.

A nested route, as the name suggests, is a Route within a Route. A Route containing one or more Routes nested within it is known as the parent route and a Route that is contained within another Route is known as the child route. When nesting Routes, the child Route path is relative to the parent Route‘s path so we shouldn’t include the parent path in its path prop.

For example, we can create a nested route by refactoring the code above, like so:

/* imports ... */ const router = createBrowserRouter(createRoutesFromElement( <Route path='/about' element={ <About/> }> {/* About renders if path starts with /about */} <Route path='secret' element={ <Secret/> }> /> {/* we can exclude /about from this path since it is relative to its parent */} </Route> ));

Using this nested route, the About component will render when the path starts with /about. If the path matches /about/secret, the Secret component will render in addition to the About component. Remember that a Route can be both a parent and child route if it is nested within a route and contains nested routes within it. The same parent/child properties would apply.

Our router is configured to render our nested route, but if we ran this code we still wouldn’t see Secret rendered below About. That’s because we haven’t told About where to render its child route element. To do this we need to make use of the React Router Outlet component in the parent About component, like so:

import { Outlet } from 'react-router-dom'; // Rendered when the user visits '/about' export default function About() { return ( <main> <h1>Lorem ipsum dolor sit amet.</h1> <Outlet/> {/* renders child element when user visits /about/secret */} <main/> ); }

Now when we visit /about/secret our router will render About and its child route component, Secret, wherever the Outlet component is defined in the parent. You can think of it as the router replacing Outlet with our defined child route.

When using nested routes we can also make use of index routes. An index route is a Route that uses the index prop instead of a path prop and is special because it renders on its parent’s path. For example:

/* imports ... */ const router = createBrowserRouter(createRoutesFromElement( <Route path='/about' element={ <About/> }> {/* About renders if path starts with /about */} <Route index element={ <IndexComponent/> }> /> {/* Will render when the path is /about */} <Route path='secret' element={ <Secret/> }> /> {/* Will render when the path is /about/secret */} </Route> ));

We can think of an index route as a default Route that will render in its parent’s Outlet when the path matches the parent path exactly so there’s some content in that space.

Nested routes give us fine-tuned control over what, when, and where certain elements appear within their parent Route. Let’s practice what we’ve learned by adding some nested routes to our application.

Instructions

Task 1

In the running application, navigate to the sign-up form and choose a username. Then navigate to the new “Profile” link that will appear. The URL will change to /profile and we should see the username we just entered, followed by a link to an “Edit” page. Try clicking on this link – we’ll notice that the URL changes, but we get a 404 error.

The EditProfileForm component should render when the URL changes to /profile/edit but it is currently not being rendered by the application. Let’s fix that with a nested routing approach.

First, in App.js, let’s define a Profile child Route for the path /profile/edit that should render EditProfileForm. Note that navigating to /profile/edit still won’t render correctly (we’ll fix this next).

Hint

Recall that we can define a nested Route like:

<Route path="/icecream" element={ <Icecream />} > {/* renders when path starts with /icecream */} <Route path="flavors" element={ <Flavors/> } /> {/* renders on path /icecream/flavors*/} </Route>

Notice that child Route path prop is relative to parents.


Task 2

When running the application and navigating to /profile/edit we’ll notice that we get no error (404) but the EditProfileForm still isn’t rendering alongside Profile. Let’s fix this by adding an Outlet in Profile. Navigate to Profile.js and import Outlet from react-router-dom.

After importing Outlet, add the Outlet component under the Link component. In the running application if we navigate to /profile we’ll see an “Edit” link which we can click and see the EditProfileForm render under it. If we fill out the username input and click “Edit” we’ll see the Profile and EditProfileForm rendered together.

Hint

Recall that when using nested routes we need to specify where the child route needs to be rendered in the parent route. For example:
/* In App.js */ <Route path="/icecream" element={ <Icecream />} > {/* renders when path starts with /icecream */} <Route path="flavors" element={ <Flavors/> } /> {/* renders on path /icecream/flavors*/} </Route> /* In IceCream.js */ export default function IceCream() { render ( <div> <h1>IceCream<h1/> <Outlet/> {/* Where child route component should be rendered */} </div> ); }

Task 3

In the running application, when we navigate to /categories we see a list of article categories rendered. When we try to click on one of these links (like html) notice your path changes to /categories/html and we get 404 error. If we look at the Categories.js component we’ll notice an Outlet defined but in App.js we haven’t defined a Route for the Category component. Let’s fix that.

In App.js, define a child Route for the Category Route that renders when the path matches a path like /categories/html or /categories/javascript.

Hint

Recall that nested routes are relative to their parents so we don't need to include its parent `path` in its `path` prop. We can use nesting with URL params like:
<Route path="/icecream" element={ <Icecream />} > {/* renders when path starts with /icecream */} <Route path=":flavor" element={ <Flavor/> } /> {/* renders on path /icecream/peacan or /icecream/vanilla*/} </Route>

Take this course for free

Mini Info Outline Icon
By signing up for Codecademy, you agree to Codecademy's Terms of Service & Privacy Policy.

Or sign up using:

Already have an account?