We're going to use React Router!
Client-side routing isn't strictly necessary for this application. However, client-side routing will let our single page app (SPA) keep the url in synch with what the user is seeing and doing as the page content changes. This is useful for deep linking and search engines!
This Todo app will have two urls or application-states (not to be confused with component states): the root url (/
) and a url to view all todos (/todos
).
There is a lot to learn about React Router, and we'll just be scratching the surface.
- Install
react-router
as a dependency withnpm install --save [email protected]
. If you get errors on the next few steps, confirm that you have it installed by checkingpackage.json
.
Note: react is still in development, and modules like
react-router
may change. This lab's solutions usereact-router
version 3.0.0. The v3 documentation can be found through ReactTraining.
- Make a
config
folder insidesrc
and aroutes.js
file inside that. Theroutes.js
file will contain the app's routes:
$ mkdir src/config
$ touch src/config/routes.js
- Fill in the contents the
routes.js
file:
// src/config/routes.js
import React from 'react'
import {Route} from 'react-router'
import App from '../App'
export default (
<Route path='/' component={App} />
)
- The
Route
component comes fromreact-router
, and the snippet above uses thisRoute
component to create a route for the root path('/'
).Route
also needs to know what component should be rendered when the user navigates to that path. Here, the component to render is theApp
component defined earlier.
Notice that the code imports
React
from'react'
but uses{}
to import{Route}
from'react-router'
. What's the difference?
Using
{Route}
imports one specific module - theRoute
module - fromreact-router
- and names itRoute
.
Without the
{}
, the import it would have grabbed all ofreact-router
functionality. Check out the react router v3 source code to seeRoute
and other modules withinreact-router
.
- The
src/config/routes.js
file sets up a route, but it's not connected to any of the app's other files yet. Referencing the code below, updateindex.js
to use React Router now instead of just rendering theApp
Component.
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Router, browserHistory} from 'react-router'
import routes from './config/routes.js'
ReactDOM.render(
<Router routes={routes} history={browserHistory}/>,
document.getElementById('root')
);
-
Think critically about the code above. What is it doing? How can you find out about less familiar pieces like the
Router
andbrowserHistory
modules? -
If everything is connected correctly, you should still see the hello world header showing when you visit the route you set up!
- The view on the
/
path will get more complex, so it makes sense to start splitting its contents into small components. Create acomponents
directory and aHeader.js
file inside it.
$ mkdir src/components
$ touch src/components/Header.js
- In the new header component file, add a
render
method thatreturn
s JSX for a more todo-appropriate header tag.
// src/components/Header.js
import React, {Component} from 'react'
import {Link} from 'react-router'
class Header extends Component{
render(){
return (
<header>
<h1><Link to={'/todos'}>React Todos</Link></h1>
</header>
)
}
}
export default Header
- The
Link
component is new in this file. What do you think it will do?
click here to check your guess for Link
Link
creates a link to another route (similar to href
in an HTML a
tag).
- Update
src/App.js
to render theHeader
component.
// src/App.js
import React, { Component } from 'react'
class App extends Component {
render() {
return (
<div className="App">
<Header />
</div>
);
}
}
export default App
-
Check your page again - what has changed? Why? Once you carefully read any error messages, move on to the next step!
-
Add a line to
src/App.js
to actually import theHeader
component:
import Header from './components/Header'
-
Try clicking on the React Todos link. You should see a warning in the console:
Warning: [react-router] Location "/todos" did not match any routes
. Does it make sense? Where are your routes defined, so you can check? -
Confirm that
config/routes.js
only has a reference to'/'
; there's no route for/todos
yet. Make a note in yourconfig/routes.js
file to remind yourself to add that route later!