React + Redux Tutorial Part II: React Router and Container Components

Using React Router


This is Part II of a eight part series on building a CRUD application with React + Redux. You can view the code for this project here. You can view the table of contents here


Let's begin by using React router to connect some basic components.

We'll configure our routes in src/routes.js.

import React from 'react';  
import { Route, IndexRoute } from 'react-router';  
import App from './components/App';  
import HomePage from './components/home/HomePage';  
import CatsPage from './components/cats/CatsPage';  
import CatPage from './components/cats/CatPage';

export default (  
  <Route path="/" component={App}>
    <IndexRoute component={HomePage} />
    <Route path="/cats" component={CatsPage} />
  </Route>
);

Here, we're using React Router's Route and IndexRoute to tell our React app which components to match to which URLs.

With this configuration, our app knows to respond to any requests nested under the / root path with the App component. All of the routes and corresponding components nested under that initial route designation will be treated as children of the App component.

Let's take a closer look at how we've configured those children.

First, we use the IndexRoute to set the default page to the HomePage component. The, we map the /cats URL to the CatsPage component.

Let's go ahead and define these components now.

The App Component

Our top-most component, the App component, is responsible for two things.

First, it will render a simple Header component that we'll define in src/common/Header.js. Secondly, beneath that header, it will render it's children.

Let's take a look:

// src/components/App.js

import React, {PropTypes} from 'react';  
import Header from './common/Header';

class App extends React.Component {  
  render() {
    return (
      <div className="container-fluid">
        <Header />
        {this.props.children}
      </div>
    );
  }
}

App.propTypes = {  
  children: PropTypes.object.isRequired
};

export default App;  

Go head and create a directory src/components/common. We'll define our Header component here.

// src/components/common/Header.js

import React, {PropTypes} from 'react';  
import { Link, IndexLink } from 'react-router';

const Header = () => {  
  return (
    <nav>
      <IndexLink to="/" 
        activeClassName="active">Home</IndexLink>
      {" | "}
      <Link to="/cats" activeClassName="active">Cats</Link>
    </nav>
  );
};

export default Header;  

Here, we're using the <IndexLink> and <Link> components made available to us by React Router to build out a navbar that links to the various pages of our application.

Okay, back to our App component. The App component will propagate the space reserved by {this.props.children} with the appropriate child component, as dictated by the router.

But how will the App component get added to our real HTML document?

Recall earlier that we said that the src/index.js file was the entry point for our application. This where we want to put the code that will add our route configuration, and thus our component tree, to the page.

Let's take a look:

/*eslint-disable import/default */
import 'babel-polyfill';  
import React from 'react';  
import { render } from 'react-dom';  
import { Router, browserHistory } from 'react-router';  
import routes from './routes';

render(  
 <Router history={browserHistory} routes={routes} />,
 document.getElementById('app')
);

Note that we're using browserHistory as our Router's history. browserHistory is the recommended history for URL manipulation with React Router, allowing us to build semantic URLs that look like /cats/new or cats/7.

Okay, we've configured our routes, constructed our parent component and taught it how to render its children, and we've used the React DOM's render method to add the React element that is our component tree to our real HTML DOM.

Now we're ready to build our CatsPage component--the "index" page of our app. Before we do though, we need to connect our React app to our Rails API, so we can fetch all the cats!

Part III: Async Redux >>

subscribe and never miss a post!

Blog Logo

Sophie DeBenedetto

comments powered by Disqus
comments powered by Disqus