Codementor Events

Use React-Router with Ease

Published Mar 13, 2017
Use React-Router with Ease

We will be using a sample app that I created in one of my previous posts. Click here to get the sample app or read Simplest React App Setup to do it yourself.

Introduction

According to the docs,

React Router is a complete routing library for React. React Router keeps your UI in sync with the URL. It has a simple API with powerful features like lazy code loading, dynamic route matching, and location transition handling built right in. Make the URL your first thought, not an after-thought.

Setting up React routing is only needed for applications that have more than one page. This post is about the basic set up. In my next post, we will take a deeper look into react-routing.

Set Up

If you followed the instruction above, you should have a sample app set up.

To start with, let’s install react-router.

Run

 	npm install --save react-router

Currently, our app is a single page app, so let's create two components: About.js & AppContainer.js. About.js will be the component for our about page while AppContainer.js will contain the generic content that all pages need to have. For example, the navbar.

Run

 	touch components/About.js components/AppContainer.js

copy and paste this into About.js.

    import React from 'react'
    const About = () => <h1>This is an about page</h1>
    export default About

also, copy and paste the code below into AppContainer.js

    import React from 'react'
    import { Link } from 'react-router'
    const AppContainer = props => {
      return (
        <div>
          <Link to='/'>Home</Link>
          { ' | ' }
          <Link to='/about'>About</Link>
          {props.children}
        </div>
      )
    }

  export default AppContainer

Next, let’s create a routes.js file.

Run

  touch routes.js

then copy and paste the code below in it.

    import React, { Component } from 'react'
    import { Route, IndexRoute } from 'react-router'
    import HelloWorld from './components/HelloWorld'
    import About from './components/About'
    import AppContainer from './components/AppContainer'
    export default (
      <Route path='/' component={AppContainer}>
        <IndexRoute component={HelloWorld} />
        <Route path='/about' component={About} />
      </Route>
    )

The next thing is to update the app.js file to reference routes.js and no longer HelloWorld.js via Router component from react-router.

Delete the code in app.js then copy and paste this

    import React from 'react'
    import ReactDOM from 'react-dom'
    import { Router, hashHistory, browserHistory } from 'react-router'
    import routes from './routes'
    ReactDOM.render(<Router routes={routes} history={hashHistory} />, document.getElementById('app'))

Router has a property called history. React-router provides two different kinds of history that can be passed into it. Most setup favour browserHistory over hashHistory because hashHistory is not SEO friendly and its URLs are ugly.

Now, let's start our server and see what we have.

Run

  npm install && npm start

Now, if you navigate to the app on the browser, you should see HelloWorld component. Also, when you click the About link, you should see the About component.

If you would like a cleaner SEO friendly URL, or you are using this in production, then browserHistory is the way to go. You may want to read more about browserHistory vs. hashHistory.

Now, update the Router part of the code in App.js like so

  <Router routes={routes} history={browserHistory} />

Your app should still work as expected. You should be able to visit both pages.

If you're trying to visit the About component http://localhost:8080/about by pasting the route directly into the address bar or reloading the page, you will get

Cannot GET /about

When you're using browserHistory, you must have a server that will always return your index.html at any route. Handling this error is necessary because the users of your application might bookmark a link that is not the index route. For this tutorial, we will use an express server.

To set this up for node.js, run

  npm install --save express path

then create a server.js file

  touch server.js

and paste the configuration below into it.

    const express = require('express')
    const path = require('path')
    const port = process.env.PORT || 8080
    const app = express()

    // serve static assets normally
    app.use(express.static(__dirname + '/public'))

    // handle every other route with index.html, which will contain
    // a script tag to your application's JavaScript file(s).
    app.get('*', function (request, response){
      response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
    })

    app.listen(port)
    console.log("server started on port " + port)

Check out this link to learn more on browserHistory.

Update your webpack.config file to look like this

    var webpack = require('webpack')
    var path = require('path')
    module.exports = {
      entry: path.resolve(__dirname, 'app'),
      output: {
        path: __dirname + '/public',
        publicPath: '/',
        filename: 'bundle.js'
      },
      module: {
        loaders: [
          {test: /\.js$/, exclude: /node_modules/, loaders: ['babel-loader']}
        ]
      }
    }

Note: We have removed the main settings for webpack-dev-server. It is no longer needed since we now have an express server. Visit here to learn more about webpack-dev-server.

You can start your app by running:

  webpack && node server.js

Copying and pasting a route directly should work as expected now.
Since webpack-dev-server is no longer being used, any change we make on a file will not be noticed by webpack. For watching of files to continue, a configuration tweak is needed. Let’s install npm-run-all — a module to run multiple commands on the terminal without necessarily waiting for one to finish.

Run

  npm install --save npm-run-all

then let’s update our package.json file. The scripts section should have the code below:

  "scripts": {
      "start": "npm-run-all --parallel webpack:build server",
      "webpack:build": "webpack -w",
      "server": "node server.js",
      "test": "echo \"Error: no test specified\" && exit 1"
    },

Your app can now be started with npm start .
If all went well, you should be able to visit http://localhost:8080/ and also http://localhost:8080/about.

Here's a detailed tutorial on how Server-Side Rendering with Redux and React-Router work!

Discover and read more posts from Kayode Adeniyi
get started