This step is already done for you, but here is how to install the react-router
dependency from scratch if you need to.
Two ways to install it:
- Add the dependency directly into the
package.json
file:
"dependencies": {
"react-router": "3.0.5",
}
- Add the dependency using the command line:
yarn add react-router -E
React Router is very well documented, so the best thing to do is to read the introduction to become familiar with the key concepts of the library.
The router configuration is done in the index.js
file.
First, import several things from the react-router
package:
import { Router, IndexRoute, Route, browserHistory } from 'react-router'
Then create the router:
class RoutedApp extends Component {
render() {
return (
<Router history={browserHistory}>
<Route path="/" component={WineApp}>
<IndexRoute component={RegionsPage} />
<Route path="regions/:regionId" component={WineListPage} />
<Route path="regions/:regionId/wines/:wineId" component={WinePage} />
<Route path="*" component={NotFound} />
</Route>
</Router>
);
}
}
And render it into the DOM:
ReactDOM.render(<RoutedApp />, document.getElementById('root'));
The Router
is the top-level element of the router configuration hierarchy. It uses the browserHistory
strategy - based on HTML5 history API - to manipulate the browser URL.
The first Route
element is mapped on the /
path and references a container component (WineApp
) that will render the router's current page.
This is the entry point of our app and it must look like this:
export class WineApp extends Component {
render() {
return (
<div className="container">
<h1 className="center-align">Open Wine Database</h1>
<div className="row">
{this.props.children}
</div>
</div>
);
}
}
The concrete routes of our SPA are defined as children of this top-level route. The IndexRoute
is the default route for the /
path and will render the RegionsPage
component. The WineListPage
component will render when the path is regions/:regionId
and the WinePage
component will render when the path is regions/:regionId/wines/:wineId
.
So :
- when the URL is
/
, the router will render<WineApp><RegionsPage /></WineApp>
- when the URL matches
/regions/:regionId
, the router will render<WineApp><WineListPage /></WineApp>
- when the URL matches
/regions/:regionId/wines/:wineId
, the router will render<WineApp><WinePage /></WineApp>
The RegionsPage
, WineListPage
and WinePage
components do not exists yet. You can create basic versions of these components just to quickly test the router.
The right place to create the RegionsPage
is into the Region.js
file, next to the Region
component. This is the same rule for WineListPage
(into WineList.js
) and WinePage
(into Wine.js
).
A simple version of the RegionsPage
component is:
export class RegionsPage extends Component {
render() {
return (
<div>Regions</div>
);
}
}
For the two other components, the path parameter values are available via the component props. So a simple version of the WineListPage
component is:
export class WineListPage extends Component {
render() {
return [
<div>Wines</div>,
<p>Region identifier is {this.props.params.regionId}</p>
];
}
}
Do the same for the WinePage
component:
export class WinePage extends Component {
render() {
return [
<div>Wine details</div>,
<p>Region identifier is {this.props.params.regionId}</p>,
<p>Wine identifier is {this.props.params.wineId}</p>
];
}
}
Finally we define a generic route for all the unmapped paths and render a NotFound
component in that case:
<Route path="*" component={NotFound} />
The NotFound
component is a very very complicated one 😉
export class NotFound extends Component {
render() {
return (
<h1>Not Found !!!!</h1>
);
}
}
Tip: do not forget to import all these new components:
import { WineApp, RegionsPage, WineListPage, WinePage, NotFound } from './components';
Now you're ready to create the real pages of the SPA.
Go to the next step to start writing the RegionsPage
component.