Nested Routing in react-router-dom
Published: 2021-09-15 23:53:45

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nlq3mp4bkd0bfrvssrhj.png)

#What is react-router-dom?

Ever wondered how websites have custom paths? How come you can type in `https://dev.to/readinglist` and your browser knows to bring you directly to your `dev.to` reading list? Well, the website you're navigating to, in our case `dev.to`, has set up some custom routes. They either have client-side or server-side routes. Client-side routes are generally used in single-page applications. They allow for routing capabilities without needing multiple html pages. Server-side routes are used in multi-page applications, where each route returns a new html page with content.

If you're using React to build your webpage and you want to accomplish something like that, then you'll want to turn your attention to react-router-dom! React-router is a node module that makes use of the React component structure to add client-side routing functionality to a webpage.

Going forward on this blog, I'm going to assume that you have a basic understanding of Switches and Routes in react-router. If you'd like to read up on them before continuing, you can find the documentation [here](https://reactrouter.com/web)

#What is nested routing?

Nested routing is the act of "burying" routes inside each other. Continuing our `dev.to` example from before, here is an example of a nested route:

`https://dev.to/readinglist/archive`

First, you route to `/readinglist` then you route to `/archive` while inside `/readinglist`, providing more specific information while still being inside that scope.

Nesting routes helps to create more organized, and clear routes for both the developers and clients to make use of. It also helps practice some separation of concerns. You could have a `/readinglist` that brings you to your reading list and a `/archive` that brings you to your reading list archive, but what happens when you want to implement a post archive? The route `/archive` is already taken, so you'd have to name the new route `/postarchive` or something, making the routes messy and hard to follow. By nesting them, you can have `/readinglist/archive` and `/post/archive` together.

#Nested routing in react-router-dom

So, now we know that we know the advantages of nesting routes, how exactly do we do it in react-router-dom?

Lets set up a basic `dev.to` route layout first:

```javascript
//App.js

import { 
  BrowserRouter as Router,
  Switch,
  Route
} from 'react-router-dom'

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/posts">
          <p>Posts</p>
        </Route>
        <Route path="/readinglist">
          <p>Reading List</p>
        </Route>
        <Route exact path="/">
          <p>Homepage</p>
        </Route>
      </Switch>
    </Router>
  );
}

export default App;
```

This route layout has three paths currently:

| Path          | Web Display   |
| ------------- |---------------|
| `/posts`      | Posts         |
| `/readinglist`| Reading List  |
| `/`           | Homepage      |

We can set up nested routing a few ways.

We could add `/readinglist/archive` by adding a route directly like this:

```javascript
//App.js
//Inside the Switch

<Route path="/readinglist/archive">
  <p>Reading List Archive<p>
</Route>
```

Although this would work, what do we do if we want to have a lot of routes nested inside `/readinglist`? We'd have to add each one to our App.js, quickly making it cluttered and hard to follow. This is why I suggest creating a custom component to store routing logic instead.

##Routing logic component

Lets start by creating a custom component to store the routing logic for `/readinglist`: 

```javascript
//ReadingListRoutes.js

import { 
    Switch,
    Route
} from 'react-router-dom';

function ReadingListRoutes() {

    return (
        <Switch>
            <Route exact path="/readinglist/archive">
                <p>Reading List Archive</p>
            </Route>
            <Route path="/readinglist">
                <p>Reading List</p>
            </Route>
        </Switch>
    )
}

export default ReadingListRoutes;
```

We've now created our `/readinglist` route logic component, but we still have to add it to our actual routes! Lets refactor our App.js and do just that:

```javascript
//App.js

import { 
  BrowserRouter as Router,
  Switch,
  Route
} from 'react-router-dom'

import ReadingListRoutes from './ReadingListRoutes';

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/posts">
          <p>Posts</p>
        </Route>
        <Route path="/readinglist">
          <ReadingListRoutes />
        </Route>
        <Route exact path="/">
          <p>Homepage</p>
        </Route>
      </Switch>
    </Router>
  );
}

export default App;
```

As you can see, we now have it set up to where the path `/readinglist/archive` first navigates to our `ReadingListRoutes` component. Once in our `ReadingListRoutes` component, it looks for the route `/readinglist/archive`. If it finds it, it displays `Reading List Archive` on the webpage.

Our routes table now looks like this: 

| Path          | Web Display   |
| ------------- |---------------|
| `/posts`      | Posts         |
| `/readinglist`| Reading List  |
| `/readinglist/archive`| Reading List Archive |
| `/`           | Homepage      |

##Dynamic Routes

So now we've learned how to do nested routing, but how exactly can we define dynamic routes? Lets take a look at the `dev.to` url to one of my blogs:

`https://dev.to/christensenjoe/classes-in-javascript-f9g`

This url first routes to my username, then my blog title (separated by hyphens instead of spaces). But how exactly is `dev.to` doing this? It cant be hard coding every single possible username as a route.

Well, react-router-dom also provides a nice way to dynamically create routes.

Lets add a basic route to `/(username)` that will take someone to their custom homepage. I'll go ahead and create a `UserRoutes` logic component to handle some nested route functionality too:

```javascript
//App.js

import { 
  BrowserRouter as Router,
  Switch,
  Route
} from 'react-router-dom'

import ReadingListRoutes from './ReadingListRoutes';
import UserRoutes from './UserRoutes';

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/posts">
          <p>Posts</p>
        </Route>
        <Route path="/readinglist">
          <ReadingListRoutes />
        </Route>
        <Route path="/:username">
          <UserRoutes />
        </Route>
        <Route exact path="/">
          <p>Homepage</p>
        </Route>
      </Switch>
    </Router>
  );
}

export default App;
```

```javascript
//UserRoutes.js

import { 
    Switch,
    Route
} from 'react-router-dom';

function UserRoutes() {

    return (
        <Switch>
            <Route exact path="/:username/:post_title">
                <p>User Post</p>
            </Route>
            <Route path="/:username">
                <p>User Homepage</p>
            </Route>
        </Switch>
    )
}

export default UserRoutes;
```

By adding the `/:username` and `/:username/:post_title` routes, we can now dynamically create new routes. If you navigate to `/joe`, you'll be met with the text `User Homepage`, and if you navigate to `/joe/new-post`, you'll find text `User Post`.

Our routes now look like:

| Path          | Web Display   |
| ------------- |---------------|
| `/:username`  | User Homepage |
| `/:username/:post_title` | User Post |
| `/posts`      | Posts         |
| `/readinglist`| Reading List  |
| `/readinglist/archive`| Reading List Archive |
| `/`           | Homepage      |

##useParams

We've now dynamically created new routes, but how can we take advantage of them to create custom pages?

First, lets start by creating two new components, `UserProfilePage` and `UserPostPage`, and connect them up to our `UserRoutes` component:

```javascript
//UserProfilePage.js

function UserProfilePage() {
    return (
        <h1>This is ___'s profile</h1>
    )
}

export default UserProfilePage;
```

```javascript
//UserPostPage.js

function UserPostPage() {
    return (
        <h1>This is ___'s post: ___</h1>
    )
}

export default UserPostPage;
```

```javascript
//UserRoutes.js

import { 
    Switch,
    Route
} from 'react-router-dom';

import UserPostPage from './UserPostPage';
import UserProfilePage from './UserProfilePage';

function UserRoutes() {

    return (
        <Switch>
            <Route exact path="/:username/:post_title">
                <UserPostPage />
            </Route>
            <Route path="/:username">
                <UserProfilePage />
            </Route>
        </Switch>
    )
}

export default UserRoutes;
```

Now that we have separate pages, we can make use of a custom react-router-dom hook called `useParams()`. useParams allows us to grab any params from the current route at the time of invocation. For example, if we went to `/:username/:post-title`, we could grab the params `username` and `post-title`. These variables would store whatever we are currently routed to. So if we're routed to `/joe/new-post`, then `username` stores the string `joe` and `post-title` stores the string `new-post`.

Let's update our `UserProfilePage` and `UserPostPage` to make use of the `useParams()` hook to add custom messages:

```javascript
//UserProfilePage.js

import {
    useParams
} from 'react-router-dom';

function UserProfilePage() {
    const { username } = useParams();
    return (
        <h1>{`This is ${username}'s profile`}</h1>
    )
}

export default UserProfilePage;
```

```javascript
//UserPostPage.js

import {
    useParams
} from 'react-router-dom';

function UserPostPage() {
    const { username, post_title } = useParams();
    const parsedTitle = post_title.split("-").join(" ")
    return (
        <h1>{`This is ${username}'s post: ${parsedTitle}`}</h1>
    )
}

export default UserPostPage;
```

As you can see, we're using useParams to get the username and post_title. We then use them to show some custom messages to our user based on what the put in. On the `UserPostPage`, we're also mutating our `post_title` to remove the dashes and replace them with spaces.

Now, if someone navigates to `/joe/my-new-post` they'll be met with the message `This is joe's post: my new post`.

#Conclusion

React-router-dom is a great node package for React that allows for easy client-side routing. If you're creating a single-page web application, then definitely consider using it to implement static, nested, and dynamic routes. If you'd like to learn more, take a look at the docs [here](https://reactrouter.com/web)