Introducing React Router

All the work we've done so far has either been in index.js or Detail.js, but now we're going to add a third file called List.js that will render a home page for our app. From there, users will be able to select a GitHub repository, and doing so will show Detail.js as before.

So, we'll go from having just one page listing all the React commits, forks and pulls on GitHub, to having a homepage first where users can select React, React Native, Jest, or other Facebook projects of our choosing. This involves a fairly big change, so we're going to do this in two parts: first implement React Router in a way that preserves the exact behavior we have right now, then second add the new home page.

Well, that's not strictly true. To avoid having to add a server configuration, the pages React Router serves up will all start with /#/, e.g. http://localhost:8080/#/hello. This means that index.html will automatically be used to render all pages, which in turn means that React Router will be able to load the right page.

The first import brings four components, of which we'll be using two immediately and the other two shortly. Router is React Router itself, which takes a list of URLs and React components and puts the two together. Route is one individual URL mapping, e.g. the URL detail and our Detail component. IndexRoute is used as a default route; we'll get onto that soon. useRouterHistory is something I'll explain in just a moment.

The second import brings in a great deal of complexity, and chances are you don't want to know about it. In short, React Router needs a smart way to handle history. This is partly done through that # sign (known as a hash history because # is called "hash" to people who don't play music), and partly through special query keys in your URLs. These query keys aren't needed in our example and just make things look a bit ugly, so we'll be taking them out. But to take them out, we need this import line as you'll see in a moment.

With those new imports, it's time to turn to the main rendering of our app. Right now we just render a Detail component, but we need to change that so we use React Router instead. Here's how it looks in its most basic form:

So, rather than rendering our Detail component directly, we now render Router, which in turn creates the appropriate child component for the URL that gets matched. Right now we specify only one URL, /, and tell React Router to load our Detail component.

If you save those changes, try refreshing your browser. All being well, http://localhost:8080/ should update to become something like http://localhost:8080/#/?_k=7uv5b6. That's the hash history in action: that ?_k= part is a unique key used to track state between locations, but we really don't need it so we'll remove it.

At the same time, we're also going to add what might seem like a bit of a hack, but I'm afraid it's a required hack until React Router solves it permanently. You see, when you navigate from /#/someurl to /#/someotherurl, you're not actually moving anywhere – React Router just unloads the previous components and loads the new one in its place. This causes a problem with scrolling, because if the user had scrolled half way down the page before changing URLs, they would remain half way scrolled down the page for the new component.

So, the hack is this: whenever the React Router updates, we tell the browser to scroll back to the top of the document, just as it would if we were changing pages the old-fashioned way.

We can make both these changes at the same time. Replace your current ReactDOM.render() lines with this one:

It's not particularly graceful code, but it is important. The history part is what removes the ?_k= mess from our URLs, because we're using the "hash history" system with its query code setting turned off. The onUpdate part is what makes sure the user's scroll position resets when they move between components.

With those changes saved, you should be able to navigate to http://localhost:8080/ and find yourself on http://localhost:8080/#/, which is what we want. Again, removing the # sign requires server configuration that we aren't going to do here. If you'd like to read more about this, here's the React Router documentation page you're looking for.

Buy the book for $10

Get the complete, unabridged Hacking with React e-book and take your learning to the next level - includes a 45-day no questions asked money back guarantee!

If this was helpful, please take a moment to tell others about Hacking with React by tweeting about it!