MADCAP IDEA PART 5 : ADDING REACT-ROUTER

 

Last Time

 

Last time we looked at using Balsamiq mockups to prototype our screens. This post is a small one, but one that I have found slightly trickier to get to work. This time we will look at routing inside of a React application.

 

PreAmble

Just as a reminder this is part of my ongoing set of posts which I talk about here :

https://sachabarbs.wordpress.com/2017/05/01/madcap-idea/, where we will be building up to a point where we have a full app using lots of different stuff, such as these

 

  • WebPack
  • React.js
  • React Router
  • TypeScript
  • Babel.js
  • Akka
  • Scala
  • Play (Scala Http Stack)
  • MySql
  • SBT
  • Kafka
  • Kafka Streams

 

What is routing?

Routing is the act of taking a uri (with our without parameters), and finding a resource (be that a page, react component file) that matches the given uri and returning that content to be rendered.

 

What choices do we have?

When it comes to React there are not than many choices at all. We need to either hand roll our own routing mechanism which might be accomplished either using

window.location.hash
window.location.href

This is however quite a pain, and you would need to hand roll your own support for richer routes that requires route parameters such as /orders/{orderId}. So perhaps there is a better way out there already. There is of course, the https://reacttraining.com/react-router/

 

 

 

React-Router

This the defacto go to solution for routing in React. The react-router was built with react in mind, which means at its heart it is a component based router. It is quite stable and been around quite a while, The current version is v4, which is quite a different beast from the previous versions, a lot changed. So for this series of posts, and the code that goes with it, I will be using v3 of the react-router.

 

Installing react-router

To install react-router, you just need to use NPM (though this article has used a specific version of react-router)

npm install react-router --save

 

Creating the components

As I say, at its heart the react-router is a component based router. So we need some components to render, route to. For the demo all my routes are simple routes that don’t require any further parameters. But rest assure the react-router can deal with routing parameters just fine.

 

So here are the demo route components that we would like to route to.

 

class ReDirecter extends React.Component<undefined, undefined> {

    handleClick = () => {
        hashHistory.push('/contact');
    };

    render() {
        return (
             <button onClick={this.handleClick} type="button">go to contact</button>

        )
    }
}



const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const Contact = () => (
  <div>
    <h2>Contact</h2>
  </div>
)


const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

 

It can be seen that these are very simple components, but they are good enough to route to. There is also an example above of how to use the router to navigate to a new route programmatically in code, but we will talk more about this later.

 

Types of history

So now that we have some components that can be routed to, we need to just understand a bit more about history, and what we get out of the box with react-router. There is great page describing this here : https://github.com/ReactTraining/react-router/blob/v2.0.0-rc5/docs/guides/basics/Histories.md

 

The real crux of it is that there are several types of history providers that can be used with the router

 

hashHistory

Which is a simple hash history which DOES NOT need server side route support.

 

browserHistory

This type of history DOES require FULL server side route support. Which means you really need to think about how your components need to be split up and served from the server side code. This history provider does support isomorphic rendering though.

 

For me the hashHistory above was what I wanted, so I have used that.

 

 

Creating the router

Ok so now that we have talked about the types of history and talked about having components to route to, how we create the router?

 

Well quite simply we do it like this (remember this is v3 of the router, v4 may be different). Note that I am using ES6 style imports

 

import * as React from "react";
import * as ReactDOM from "react-dom";

import 'bootstrap/dist/css/bootstrap.css';
import {Nav, Navbar, NavItem, NavDropdown, MenuItem} from "react-bootstrap";

import { Router, Route, hashHistory  } from 'react-router'





ReactDOM.render((
    <Router history={hashHistory}>
            <Route component={App}>
                <Route path="/" component={Home}/>
                <Route path="/contact" component={Contact}/>
                <Route path="/about" component={About}/>
                <Route path="/redirecter" component={ReDirecter}/>
            </Route>
        </Router>
), document.getElementById('root'));

 

It can be seen that the router itself is a React component and gets rendered to a target DOM element. It can also be seen that we include a hashHistory which we imported from react-router.  Each route is added as a new Route where we match the expected route path, with the component to render.

 

I will also be showing you how to use the react-router with a bootstrap-react Navbar too, so there are imports for that too.

 

 
How does that work with a bootstrap-react navbar?

So I just mentioned I would like to use a bootstrap-react Navbar, so what does that look like. Well some of the eagle eyed amongst you may have noticed the line component={App} in the router setup we just saw. Lets have a look at that.

 

import * as React from "react";
import * as ReactDOM from "react-dom";

import 'bootstrap/dist/css/bootstrap.css';
import {Nav, Navbar, NavItem, NavDropdown, MenuItem} from "react-bootstrap";

import { Router, Route, hashHistory  } from 'react-router'


class MainNav extends React.Component<undefined, undefined> {
  render() {
    return (
     <Navbar brand='React-Bootstrap'>
         <Nav>
             <NavItem eventKey={1} href='#/'>Home</NavItem>
             <NavItem eventKey={2} href='#/contact'>Contact</NavItem>
             <NavItem eventKey={2} href='#/about'>About</NavItem>
             <NavItem eventKey={2} href='#/redirecter'>Redirect</NavItem>
         </Nav>
     </Navbar>
    )
  }
}



class App extends React.Component<undefined, undefined> {
  render() {
    return (

        <div>
            <MainNav/>
            {this.props.children}
        </div>
    )
  }
}

 

It can be seen that the App component is another React component that does 2 things:

  • Renders another component, namely MainNav (which is a bootstrap-react Navbar component, which is also shown above, where the Navbar has links  for the required routes)
  • Also renders the children of the router, which for this example will be a single component (so for the demo code will be one of ReDirecter / Home / Contact / About components)
  •  
 
What about on the fly route changes?

But what about when we are inside of a React component and we may wish to navigate somewhere else, how do we do that? Well it is done via the use of the routers history provider (hashHistory / browserHistory etc etc), here in an example of that from a simple React component that shows a button, which when clicked will perform a redirect to the Contact component, the trick is to use the history provider push(..) method to set a new route location

 

class ReDirecter extends React.Component<undefined, undefined> {

    handleClick = () => {
        hashHistory.push('/contact');
    };

    render() {
        return (
             <button onClick={this.handleClick} type="button">go to contact</button>

        )
    }
}

 

 

Demo

Ok so now we have covered all the basics, lets run the code up and see what we get.

 

When we first start we see this, where we can see the Navbar, and the address bar contains a # style address (this is due to using the hashHistory history provider for the Router)

 

image

 

We can click on the various links representing the routes, and the relevant component will get rendered by the Router. The Redirect route is shown below, where clicking the button will perform a redirect to the Contact component

 

image

 

 

Conclusion

As you can see even something as page navigation in React requires a bit of thought, and depending on what type of routing you chose to use, may even require a fair amount of server side work, which could change the entire workflow quite a bit.

 

I went for the hashHistory for this demo but for a real world production ready application, you should use the browserHistory, and ensure you have supporting server side code to deal with the expected routing requests.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: