Skip to content

Set up Routes

JP Barbosa edited this page Feb 20, 2017 · 2 revisions

As of now, we have an empty ContactList and a ContactForm wrapped into a ContactCreate component that we still haven't rendered and tested yet. To be able to access the list and the form in different pages, we're using a library called react-router-dom.

react-router-dom is one of the React Router v4 child libraries that only deal with DOM and browser routing. The way it works is fairly simple: you wrap the app in a Router higher-order component and declare the routes via a Route component that will match its path to whatever is in the browser and render the component passed to it.

Implementing React Router

yarn add react-router-dom@next
nano src/App.js
...
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
...
import ContactCreate from './containers/ContactCreate';
...
render()
return (
  <Router>
    <div>
    ...
      <div className="navbar-header">
        <Link className="navbar-brand" to="/">React Apz</Link>
      </div>
    ...
      <section className="container-fluid">
        <h2>Contacts Manager</h2>
        <div className="container">
          <Route exact path="/" component={ContactList} />
          <Route path="/new" component={ContactCreate} />
        </div>
      </section>
    </div>
  </Router>
);
...

Refresh, then try accessing http://localhost:3000, then http://localhost:3000/new. You'll see the list rendered when accessing the first URL, then the form on the second. This is because of Route, which matches the history path with the prop path, and, if it matches, the component will be rendered. On the root route, we passed an exact prop whose value is implicitly true to make Route do a strict comparison, instead of a loose one. Otherwise, ContactList would render alongside ContactCreate and any other component as long as the path was a positive match for /.

We have also substituted the a tag on the app's navbar with a Link component imported from react-router-dom. Link is just an a tag that is aware of the router that, when clicked, directs the user to the new route without refreshing the app. This way, we will gain a lot of navigation speed by not having to download every single page all the time.

Let's add a link to ContactList that leads to ContactCreate and vice-versa.

nano src/containers/ContactList.js
...
import { Link, withRouter } from 'react-router-dom';
...
<h1>Contacts</h1>
<Link to="/new" className="btn btn-primary">
  Create Contact
</Link>
...
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(ContactList));
nano src/containers/ContactForm.js
...
import { Link } from 'react-router-dom';
...
<button type="submit" className="btn btn-primary" disabled={pristine || submitting}>Submit</button>
<button type="button" className="btn btn-default" onClick={reset} disabled={pristine || submitting}>Reset</button>
<Link to="/"><i className="glyphicon glyphicon-chevron-left"></i> Back to Home Page</Link>
...
nano src/containers/ContactCreate.js
...
import { withRouter } from 'react-router-dom';
...
export default connect(null, mapDispatchToProps)(withRouter(ContactCreate));

The withRouter function wraps the component into a higher-order component that makes it aware of the router props, such as history, pathname, parameters and methods to alter the browser history. This will be useful when we need to redirect the user to a different page after doing something.

Since we want the user to return to the home page when he inserts a new contact, let's redirect them into handleSubmit.

nano src/containers/ContactCreate.js
...
handleSubmit({ name, phone, email }) {
  const { onSubmit, push } = this.props;
  onSubmit({ name, phone, email });
  push("/");
}
...

Try adding a few contacts to the list before heading to the next step.

Next step: Delete a Contact

Clone this wiki locally