Nested Routing in react-router-dom

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, i…


This content originally appeared on DEV Community and was authored by Joe Christensen

Alt Text

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

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:

//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:

//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:

//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:

//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:

//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;
//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:

//UserProfilePage.js

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

export default UserProfilePage;
//UserPostPage.js

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

export default UserPostPage;
//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:

//UserProfilePage.js

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

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

export default UserProfilePage;
//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 navigated 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


This content originally appeared on DEV Community and was authored by Joe Christensen


Print Share Comment Cite Upload Translate Updates
APA

Joe Christensen | Sciencx (2021-09-15T23:53:45+00:00) Nested Routing in react-router-dom. Retrieved from https://www.scien.cx/2021/09/15/nested-routing-in-react-router-dom/

MLA
" » Nested Routing in react-router-dom." Joe Christensen | Sciencx - Wednesday September 15, 2021, https://www.scien.cx/2021/09/15/nested-routing-in-react-router-dom/
HARVARD
Joe Christensen | Sciencx Wednesday September 15, 2021 » Nested Routing in react-router-dom., viewed ,<https://www.scien.cx/2021/09/15/nested-routing-in-react-router-dom/>
VANCOUVER
Joe Christensen | Sciencx - » Nested Routing in react-router-dom. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/09/15/nested-routing-in-react-router-dom/
CHICAGO
" » Nested Routing in react-router-dom." Joe Christensen | Sciencx - Accessed . https://www.scien.cx/2021/09/15/nested-routing-in-react-router-dom/
IEEE
" » Nested Routing in react-router-dom." Joe Christensen | Sciencx [Online]. Available: https://www.scien.cx/2021/09/15/nested-routing-in-react-router-dom/. [Accessed: ]
rf:citation
» Nested Routing in react-router-dom | Joe Christensen | Sciencx | https://www.scien.cx/2021/09/15/nested-routing-in-react-router-dom/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.