Journey into React Part 3: Navigating Between Webpages with React Router

Home/Development/Javascript/Journey into React Part 3: Navigating Between Webpages with React Router

Journey into React Part 3: Navigating Between Webpages with React Router

Hello and welcome back for part 3 of our journey into React. By now, you’ve set up your windows based work environment, and have created your first hello world app. If you’ve missed these, I’d highly recommend going back and reviewing them: part 1 is here, and part 2 is here. Our goal today will be really digging into our React app by implementing react router, the dependency that will allow us to control what “page” the user sees. There is a lot that goes in to making applications so I want us to get a decent working knowledge of one thing before moving on to the next. One of the biggest problems I ran into when learning how to make my first application was information overload. So, this tutorial and the next one will be focusing on the client side of our program.

In review, we are working on an address book application that is going to store our contacts in a Mongo database. Our application will support multiple accounts, will authenticate securely, and will provide us with the ability to add, erase, call, or email our contacts all from within the browser. So going forward we are going to start pushing our application in that direction.

You can view the completed version of part three at my GitHub repo.

Why we need React Router

Unlike a traditional website that serves different files to it’s clients (like, the home page, the login page, and the about page), React is delivering a single html file to the client. This file contains all of our applications code and depends on something called a router to “simulate” the appearance of different web pages. Whenever a user clicks a link that navigates them around our app, it’s only a command telling the application what component to display on the users screen. We can use react router to simulate different urls, and make the application feel more like a traditional website.

As that sinks in, let’s get started implementing react router into our own application.

Creating our route controller

First things first we’re going to need to implement a new dependency:

$ npm install react-router --save

Now, we’re going to create a new file in our src directory titled routes.js, which within we’ll start creating our router.

import React from 'react';  
import { Route, IndexRoute } from 'react-router';  
import App from './components/app';

export default (  
  <Route path='/' component={App}>
    <IndexRoute component={App} />
  </Route>
);

The top part should be familiar by now; we’ve imported our React dependency, and our App component, as well as the functions Route and IndexRoute from our newly installed react-router package. The new part there is the export default function where we’ve created our <Route /> We passed this route the route path (path='/') and set the component to “App”. We’ve also added an IndexRoute which (for the time being) is also pointed to the “App” component.

Here is where most of the routing magic happens. By defining the path parameter of our route, we are telling React to display the “App” component when the url is equal to this path. We’ll see how this is used a bit more down below, but first lets patch in our router so that we can use it.

Including the Router into our App

Let’s jump on over to the index.js file we have in our src directory. You’ll recall that we had imported the “App” component and plugged it into the ReactDOM.render()function. We’re going to instead implement our router so that we are delivery all of our pages to the client.

import React from 'react';  
import ReactDom from 'react-dom';  
import { Router, browserHistory } from 'react-router';  
import routes from './routes';

ReactDom.render(<Router history={browserHistory} routes={routes} />, document.querySelector('#app'));  

Notice we imported Router and a new function browserHistory here, as well as including our routes from the routes.js we just created. In our render function we’ve added the Router with the first parameter which will remember our clients browsing history across our site, and we’re defining the routes as our routes.js function. And that’s about it, go ahead and run your application again to make sure it’s still working, and meet me in the next section.

Adding a few new components

Let’s take another look forward at what our application is going to need right away. We’ll need a dashboard where we can view our contacts, and of course a login page to get in to the dashboard. We’ll also need a navigation bar to switch between pages. Let’s just make some simple components exactly like our first one, and change the contents so we can tell them apart.

src/components/dashboard.js
import React, { Component } from "react";

export default class Dashboard extends Component {  
  render() {
    return (
      <div>
        This is the dashboard
      </div>
    );
  }
}
src/components/login.js
import React, { Component } from "react";

export default class Login extends Component {  
  render() {
    return (
      <div>
        Login Form will go here
      </div>
    );
  }
}

And now let’s make a very simple navigation list so we can move between them (once we connect everything together of course). We’re going to import a new function here from react router as well that we’ll use much like standard <a /> tags in html.

import React, { Component } from "react";  
import { Link } from 'react-router';

export default class Navigation extends Component {  
  render() {
    return (
      <div>
        <ul>
          <li><Link to="dashboard">Dashboard</Link></li>
          <li><Link to="login">Login</Link></li>
        </ul>
      </div>
    );
  }
}

Now that we’ve created two new pages for our website, let’s get it imported into our router.

Implementing new pages into the router

So we’ve created some new components and we want them to act as pages for our website. Let’s jump back over to our routes.js file and add them like this:

import DashBoard from './components/dashboard';  
import Login from './components/login';

export default (  
  <Route path='/' component={App}>
    <IndexRoute component={DashBoard} />
    <Route path='dashboard' component={DashBoard} />
    <Route path='login' component={Login} />
  </Route>
);

You’ll recognize the IndexRoute, but notice we changed the target component to the DashBoard. We’ve also added two new paths that point to the new components we just made. Make sure the path here is equal to the link to={} destination in our navigation component as well.

Now, we need to bring this all together somehow. In our app.js file we previously had the words “hello world” within our rendered div. We’re going to swap that out for a property that will represent the entirety of our website.

import Navigation from './navigation';

export default class App extends Component {  
  render() {
    return (
      <div>
        <Navigation />
        {this.props.children}
      </div>
    );
  }
}

You can think of the app.js file as the entirety of our application. Within the rendered div of our “app” component everything our clients see will be displayed. So by importing the navigation.js file we are telling our application to display the navigation bar at the top of the div, and underneath it all of the other components {this.props.children}. The router than controls which components are displayed.

We can now load up our application again and and we’ll see our ugly ul, and the dashboard component. If you click the links you’ll notice the url changes and it should display the appropriate component.

It doesn’t look too pretty, but we’ll fix that next time. For now, sit back and enjoy your work – you’ve just created your own multi-page React app using react router. You’ve already experienced the power behind the component based style of React by changing and improving your app.js file to accommodate your new router, and making small changes to your index.js file that dramatically impacted the overall project. It’s a big step – but are you ready to take some more in our Journey into React?

Until next time, happy coding!

By | 2017-01-20T18:48:59+00:00 May 22nd, 2016|Development, Javascript|14 Comments

About the Author:

React.js developer, web designer, devops engineer, and business owner.
  • sanjiv kumar

    Hi David, First of all thanks for this great series of articles. Now coming specifically to Part 3, not sure where I am going wrong but my application worked only till “Including the Router into our App”. You ask us to verify that the app still works in this section, which I did and it works fine.
    Something goes wrong later. I added the login.js, dashboard.js & navigation.js under components. Modified the routes.js next. I made sure the “path” values match with that of “Link to” values in navigation.js. Modified app.js too. And then i start the server with “npm run dev”. At the browser I try to invoke the index.html with http://localhost:8080/. And then i get a blank page. Appreciate any help.
    Regards,

    • You’re welcome! Getting the router hooked up into your app can be really easy to mixup and will cause the whole app to no longer work! Could you share your code so I can help you figure out what’s wrong?

    • Hey Sanjiv, figured it out! You were missing some dependencies in your `index.js` file. In the last section I mentioned adding them, but it wasn’t very clear in this tutorial that it was supposed to be there (so I updated it). Thanks so much for asking and pointing out this flaw for me!

      Your missing code in src/index.js:

      “`
      import React from ‘react’;
      import ReactDom from ‘react-dom’;
      “`

      • sanjiv kumar

        Hi David, Thank you for taking the time to investigate. But I still got the blank page. The problem was also this:
        import ReactDom from ‘react-dom’;
        But we use it as:
        ReactDOM.render(…
        So changed it to: ReactDom.render. It is fine in Part 2 but in this article, Part 3 above, it needs a small correction. It works now. Thank you very much. Going now to the next article in this series.
        Regards,

        • Anthonie

          I apologize, could you specify how you fixed the problem a little more?

          • sanjiv kumar

            Hi Anthonie, Not sure where you are stuck, but these are the things I did:
            – added the 2 imports David has mentioned in the above comments to index.js
            – changed ReactDOM.render to ReactDom.render OR you could import react-dom as ReactDOM instead
            – Navigation component should be in navigation.js file
            – also you could check David’s source for this tutorial 3 at: https://github.com/dmeents/react-node-tutorial/tree/journey-part3/
            Hope this helps

          • Anthonie

            It did, thank you so much

          • Sorry there’s been some confusion on this step – thank you for pointing it out to me! When I free up I’ll clarify a bit more to prevent this from happening in the future. A step that helps me identify problems is viewing the browser console when an app isn’t working. Any errors that React is noticing should kick something there to help you debug. You can view the console by right-clicking the page and selecting “inspect element”. The console should be one of the tabs at the top, or already at the bottom of the window that pops up. Hope this helps debugging in the future!

          • Still unfixed. 😉
            In third code block, the fiths line.
            Actual you write: ReactDOM.render…
            But it has to be: ReactDom.render…

          • There we go….that should do it. Thanks Raffi!

  • Anthonie

    Is there any way to get rid of the links once you go to the new page? Because if they stay at the top of the page, they seem more like tabs than actual transitions to new files.

  • Dominic Gichuhi

    Hey. that was nice. like a rollercoaster