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, 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 or 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 that 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 require 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 assured, 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.
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 do 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 that 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. Let's 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.), here is 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, let's 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).

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.

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.