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!