Client-side routing with react-router (part 2)

How to perform client-side routing with react-router in a universal web application.

Prerequisite

Refactor

Create a directory that will hold all our view components:

$ mkdir views

Then move and rename our main component inside the directory:

$ mv Component.jsx views/Layout.jsx

Layout

I’m adding a displayName so the component name shows up in React Developer Tools (line 4). Also, we’re going to render the component’s children underneath the button (line 19):

views/Layout.jsx

Why do we render this.props.children? Because Layout will act as a container component (once the routes are configured) and children is a special prop for the children elements.

Currently, the route / renders Layout:

<Route path='/' component={Layout} />

But if we want to add a route /about that renders About inside Layout, then we do the following:

<Route path='/' component={Layout}>
<Route path='about' component={About} />
</Route>

In other words, the component hierarchy for /about will look like this:

<Layout>
<About />
</Layout>

Views

Create views/Index.jsx, which will render for route /:

views/Index.jsx

Create views/About.jsx, which will render for route /about:

views/About.jsx

Routes

Now let’s update our ReactRouter routes (lines 5, 16–19):

Each Route path is mapped to a component and IndexRoute is the default route for the parent route so you don’t have to specify path.

Server Error

When you go to http://localhost:3000/ and refresh the browser, you get the following error:

TypeError: Converting circular structure to JSON
at Object.stringify(native)
at [object Object].module.exports.React.createClass.render (Layout.jsx:21:56)

Why did we get this error? Well, in the previous tutorial we merged ReactRouter’s props with our custom props to keep universal rendering.

But ReactRouter’s props also contain our components as React elements and since we’re using the children prop, it now has a circular structure.

Thus, we need to separate our custom props from ReactRouter’s props. To do that, we’ll give our props the namespace custom (you may use any name as long as it doesn’t conflict with a ReactRouter prop name).

Update the router when it mounts on the client (line 10):

routes/routes.jsx

Update the router when it matches on the server (line 16):

routes/index.jsx

Update Layout (lines 9, 13, 17, 22):

views/Layout.jsx

Now when you refresh your browser, it works! You can verify that the prop is namespaced with React Developer Tools or by inspecting the JSON output in the HTML.

Go to http://localhost:3000/about to confirm that server-side routing is working.

Link

Now let’s make sure that client-side routing works.

We’ll add Link to Layout (lines 2, 22–29):

views/Layout.jsx

As you can see, Link takes the prop to which is simply a location descriptor.

Refresh your browser once again and try clicking on the links. You’ll notice that the routes and views update without a full-page refresh. Nice!


So what’s next? In the next tutorial, we’ll set up Redux in our universal application. Feel free to check out the code for this tutorial as well as other videos in my React playlist.