React Router 4 Gotchas

Djoe Pramono
3 min readMay 30, 2017

--

Many of you probably already knew, react-router is now at version 4. It comes with several changes but unfortunately, the tutorials that are floating around in the internet today may not be necessarily up to date. This can be frustrating for some, well … it was for me. Thus I’m writing this blog, documenting the gotchas, I learnt along the way.

Different router for different environments

In version 4, there are two different kind of routers:

  • react-router-dom to be used in a browser
  • react-router-native to be used in a react-nativeapp

For me, I was building a static website so I used react-router-dom

import { HashRouter, Route, Switch } from 'react-router-dom'

This is actually pretty nifty, because if I want to port my code to react-native I can just update the import statement.

<Router> is gone

As you probably have noticed by now, <Router> is gone. It is replaced by <HashRouter>and <BrowserRouter>. If you keep using <Router>, you will see this as console warning

Warning: Failed prop type: The prop `history` is marked as required in `Router`, but its value is `undefined`.

So what are the new routers for?

  • <HashRouter>, basically it uses the hash in the URL to render the component. Since I was building a static one-page website, I needed to use this.
  • <BrowserRouter>, it uses HTML5 history API to render the component. The history can be modified via pushState and replaceState. More information can be found here

A <Switch> for exclusive multiple <Route>s

If your app have multiple routes like mine. You need to wrap the routes with <Switch>

<HashRouter>
<Switch>
<Route exact path="/" component={App} />
<Route exact path="/about" component={About} />
</Switch>
</HashRouter>

Without <Switch> you probably would end up with the following error

Uncaught Error: A <Router> may have only one child element

If you google that, you might end up with a suggestion to put <div> instead. This works fine and the error will be gone. However, this makes the routes inclusive, which means if a path can match two routes, both components will render.

Contrary to my initial thinking the syntax exact in the <Route> does not make the route exclusive, i.e. the router will still check the next rule instead of stopping.

So please use <Switch> instead. For more information please read this

Passing parameters

To pass a parameter in, it is actually quite straightforward.

<Route exact path="/profile/:id" component={Profile} />

If you setup a route as the above, id is then accessible as a String in the Profile’s props via match.params.id. So in Profile.js I can write something like

class Profile extends React.Component {
render() {
return (
<div>
<h1>Profile</h1>
<h2>{this.props.match.params.id}</h2>
</div>
);
}
}

So what is the gotcha?

I intended to put my one-page app in Github Pages or Amazon S3. Thus my app is considered as static. I was oblivious about the difference of BrowserRouter and HashRouter. I was under impression that using BrowserRouter is the recommended way regardless if my react app is static or backed by a dynamic server.

The gotcha is, if I use BrowserRouter, it will NOT take the hash url into account. Thus when I tried to access http://localhost:8080/#/profile/1, the router will just stop at the first rule i.e.

<Route exact path="/" component={App} />

Once I switched BrowserRouter to HashRouter, everything worked as normal.

Code Overview

For those who are interested, below is react routing code

import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter, Route, Switch } from 'react-router-dom';
import App from './App.js';
import About from './About.js';
import Post from './Profile.js';
ReactDOM.render(
<HashRouter>
<Switch>
<Route exact path="/" component={App} />
<Route exact path="/about" component={About} />
<Route exact path="/profile/:id" component={Profile} />
</Switch>
</HashRouter>
, document.getElementById('app')
);

Note that I am using ES6 class approach which is recommended by React since version 0.13

That’s all folks!! Thanks for reading.

Awesome links that helped me

--

--