Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
  • Overview
  • Transcript

1.2 How It Works: React Router

In this lesson, we’ll explore React Router for a sample app consisting of a dashboard, categories, products, and reviews. I’ll show you how to create the route configuration to navigate between these logical pages.

We’ll take a look at the router API with browserHistory, <Router>, <Route>, and <Link> components. We’ll gradually build up the route configuration, solving the challenges that arise one by one.

Code Snippet

The snippet below shows how the routes are set up for our sample app.

    import {About} from "./components/about";
    import {ReviewList} from "./components/review-list";
    import {Product} from "./components/product";
    import {Category} from "./components/category";
    import {Unknown} from "./components/unknown";
    import {Dashboard} from "./components/dashboard";
    import {browserHistory, Router, Route, IndexRoute} from "react-router";
    import ReactDOM from "react-dom";
    import {Shell} from "./components/shell";

    const root = (
        <Router history={browserHistory}>
            <Route path="/" component={Shell}>
                <IndexRoute component={Dashboard}/>

                <Route path="category/:category" component={Category}>
                    <Route path="product/:product" component={Product}>
                        <Route path="reviews" component={ReviewList}/>

                <Route path="about" component={About}/>
                <Route path="**" component={Unknown}/>

    ReactDOM.render(root, document.querySelector('main'));

Related Links

1.How It Works: React Router
2 lessons, 15:19

Free Lesson

How It Works: React Router

1.2 How It Works: React Router

[SOUND] Now, before we talk about React Router, let's look at traditional navigation in complex web applications. Normally, you'll break down your application into a bunch of physical pages. And then via links, it will navigate between them. Each time resulting in a page refresh. In single page applications involving React, you can't have the luxury of a page refresh. Instead, all of the functional areas can still be navigated via the URL. But breaking them down into a bunch of logical pages. You can assign specific URL segments to each of these logical pages and then navigate to them. The root logical page will of course be slash. And the nested page such as featureC can have a URL segment like /featureA/featureC. With these concepts about logical pages and URL segments that map to them. We can now talk about the react-router model. It all starts with a router, which is the main orchestrator inside the library and helps in navigating between routes. Every route has a visual counterpart, which is the React component. And can also optionally have a path that participates in the URL matching. Via links, you can navigate between these routes. And that essentially is the react-router model. One thing to observe over here is that you can have nested routes and a visual containment of components. This allows you to create a common layer that is shared across all the nested routes. To help understand these concepts better, let's look at a sample app. In this app, we'll have a dashboard that'll show you a bunch of categories. And each category will have a bunch of products. And product can have a number of reviews. And via links, you'll be navigating between these visual components. Which are also mapped to routes and URLs as you can see over here. The colon-prefixed names that you see over here are called params. Which can be used to pass parameters into the route. Let's look at all of these as we build the sample application. Our sample app follows a pretty standard React setup. It has webpack as the build tool. With Babel to transpile the ES2015 code to ES5, and also using Bootstrap v4. And finally, we'll have the npm script to kick off the webpack-dev-server for the live reloading development experience. The one thing I do want to point out in the webpack.config. Is the use of the publicPath for the output property. And the historyApiFallback for the devServer. This allows all the client side route URLs to fall back to index.html and not result in an actual page refresh. Now with the setup out of the way, let's look at the data that we'll be displaying for our app. It's an auto generated data from the json-generator.com. All we're doing here is showing you a bunch of categories on the dashboard. So I have an area of categories. And each category has an area of products. And each product has an area of reviews. It's a pretty simple setup and that's what we'll be rendering in our app. All right, so let's jump into main.jsx, which is the entry point into our app. I'm gonna setup a very simple React boilerplate, which is to render that root node using ReactDOM.render. This is just to test out and see if everything is working properly. So now I can just open up the localhost 8080, which is a webpack dev server. And we can see that it's running properly. It's time we make things more interesting. Let's pull in the React Router starting with the Router component. Inside the Router, we're gonna declaratively configure the various routes, starting with the root route. Here, it's just for the path, which is just a string starting with slash. And then the component is the visual component that will be used to render the layout of the application. I'm gonna call it the Shell. With just that little change, we can now go back to our app. And see that the root component, which is identified by the slash, is now rendered by the Shell component. For the beginner's sake, what is this hash suffix string at the end of the URL? That's because the router, by default, uses the hash history. And that's what puts the hash at the end. Instead, what you want is a clean URL. And for that, we need to switch to the browser history. We can do that by specifying the history property and setting it to the browserHistory. Now we can go back and remove the suffix and it'll render properly with a clean URL. With the Shell being the root of our application. It provides a common layout for the rest of our nested routes. And for that to work, it needs to provide a placeholder. Where the nested routes' visual content can be injected. We do this with the use of the props.children. To see this in action, let's add a nested route called Dashboard. And the path itself will be /dashboard. And it'll be rendered by of course by the Dashboard component. With this change, if we go back to our app and navigate to /dashboard. We can now see a dashboard of categories. Just one little improvement you can make over here. What we really want is that the dashboard itself be loaded as soon as you navigate to the root route, which is slash. Wouldn't that be nice? And if you did, it's actually a very simple change. Instead of the Route, we just call it the IndexRoute. So as soon as you go to slash, the IndexRoute becomes the dashboard. And gets injected into the placeholder created inside the Shell component. Now if we revisit our app, well, it doesn't load. Because there's no dashboard route anymore. We'll fix that in a sec. Now let's change that to slash. And you can now see that the dashboard is loaded at the root route. Now that's cool and much better. All right, let's fix a case where you entered a bad route. But you don't want to React Router to fail with an exception. Instead, we want to handle it more gracefully. You can do this by specifying a special route and you will need a path of star star. You gotta be careful to specify this route as the last route. Because, by default, the route matching happens from top to bottom. We'll add the component, a Unknown component so that we can show a nice message when you go to a bad route. So now when you go back to /dashboard, you will know that this route doesn't exist. So we can actually tell the user, you know what? This is bad, let's go back home. Now the interesting thing to note is inside the Unknown component. The way we navigate back home is by using the Link component. By using the to property, you can specify any absolute path and navigate to that. Note that this has to be an absolute path. So now if you go back and click on Go Home, we'll go back to the dashboard. In fact, we can go to any bad route and see that we are jumping to the unknown route. And then from there, go back home. Now let's go back to our route configuration and add a few more routes. Starting with the category route. This is nested inside the root route. And take's a path which has a parameter in it, which is the colon-prefixed category. And the component that will be rendering it is the Category component. Because of the visual containment inside the Shell, the category replaces the dashboard when you navigate to it. When you click on the View button, which is actually done through the Link component. You navigate to the category, and now we can see that the category replaces the dashboard. And the rest of the Shell still remains, which is the header and the footer. And with this, you can see that by creating a nested route, we can also create visual containment inside our application. Now let's add one more nested route for the product. And this too takes in a parameter with the :product and points to the Product component. But there are a few things I wanna point out in the Category component. First is the use of the props.params. This is something that is passed in by the React Router. And it is also part of the route configuration and when it specified the path. If you remember, the colon-prefixed names that you specified over there are exactly the names that you do see in the props.params. So category and product are the two properties you'll receive from the router. The Category component also has a nested route for products. And provides visual containment for this particular route. And this is done with the use of the props.children. This is the placeholder inside which we'll render our Product component. And storing it in the contents variable and rendering it inside the Category component. So when we click on the Category link inside the dashboard, we pass in the category name as a param. And that's what takes us to the Category page. Inside the Category component, we show you the list of products on the left. And by clicking on the links on the left, you can show the product details on the right. It's more like a module detailed component over here. As you click on the product links, you will see that the URL also changes. And passes in the parameters for the category name and the product name. It passes params with the Link component. Here you can see that we're looping through the products. And then creating a link that takes in the category name and the product name. Now let's add one more nested route for the reviews. We'll go back to our main.jsx. And in the Route configuration, we'll add one for the reviews inside the product route. As you can imagine, the Product component will have a placeholder with the props.children to render the Review component. If we go back to our browser, we can see that when you navigate to a product, you'll see the product details over there. And in there, you have a link to see the reviews. You can click on that and Show and Hide Reviews. But there's something interesting going on. When you click on that link, you see that the link text actually changes between Show Reviews and Hide Reviews. As well as the URL, of course, changes to include the reviews or not have it. Let's see how this is done inside the Product component. The first thing to note in the Product component is the use of the @withRouter. This gives us a way of getting the router instance as a prop on the component. And that's exactly what we're doing by destructuring the router along with the category and product params from the this.props. The @ syntax that you saw above is the use of decorators. And to enable that, we have to include a special plugin called transform-decorators-legacy inside of webpack.config. This is just an insight to let you know that we use this plugin to get the decorator syntax. Now back in our Product component, we're gonna use the router instance to check whether a specific URL is active. In this case, whether the productReviewUrl is active. Now based on this condition, we're gonna change the URL for the Link as the last link text as you can see over here. With these changes, we can now get the Product component to show and hide the reviews. As well as change the URLs to go back and forth between the two. Now I mentioned a few times that the nested route allows you to create visual containment. But let's actually see this in action. I'll take out the reviews route from inside the product and make it a peer of the category route, making it a top level route now. Now we also need to adjust the reviews URL path. Since it needs the category and the product names, we need to include that in the URL path now. With that change, we are back to our original URL configuration. But the visual containment has changed. Now if we go back to the web page, we can see that the Reviews component is actually rendered outside, right inside the Shell. It's not inside the Category or the Product anymore. The containment has effectively changed. Of course, from a usability perspective, it makes more sense to see the reviews together with the product and the category. So I'm gonna put it back inside and just adjust the URL route to reflect the change. And with that, we are back to our previous configuration. Now I'm gonna add one more popular route for the About page. So I'll simply call it about and point it to the About component. And then back in the Shell component. I'm gonna include a link to the about route by simply adding the Link and pointing it to About. I'll also add a reference to the home route by adding a link to slash. This gives us a way to jump to the home route anytime we want. In most applications, it's common to show the active route by highlighting with some kind of a CSS class. And you can do that with the Link component by using the activeClassName property. So let's do that over here. Since we're using Bootstrap, the active property happens to be just active. The Link component literally translates to an anchor tag. So we can also add traditional class names to it. And since they're part of the navbar, we need to include the nav-link as a CSS class. So with the use of the activeClassName, you can actually see which route is currently active on the navbar. If you click on About, it highlights the about route. When you go to Home, it highlights the home route. But wait a sec, the home route doesn't seem to change between the unhighlighted and the highlighted classes. What's going on over here? The way the route gets matched is by looking at the URL path and checking if it's a prefix of the current route path. And, of course, slash is the prefix for every single route, so it's always active. Luckily, there's a property on the Link component called onlyActiveOnIndex. With this property set, an exact match algorithm will be used to check if a route is active. And that's exactly what we need for the home route. So let's set this property and check if it works. So now if we go back, we can already see that the home route is inactive. And that's because we're on the about route. If we click on Home, and the About becomes inactive. And when we go back to About, the Home becomes inactive. So it looks like it works now. But it turns out there's an easier way to do this instead of setting the property. Instead of using the Link, we use the IndexLink, and then remove the onlyActiveOnIndex property. I prefer this approach because it's more declarative and also explicitly states the kind of link you want to insert over here. And, of course, the activeClassName continues to work. Now that brings us to the end of our coffee break. We learned a variety of concepts over here. Starting with route configuration, adding an index route, creating nested routes, passing params, navigating via Link and using browser histories. Of course, all of this was done using the ES2015 syntax. There's still a lot to explore and the React Router's GitHub repo is the best place to go. Happy routing.

Back to the top