Skip to content

Set up Contact List

Pamela Argentino edited this page Feb 16, 2017 · 3 revisions

Now that we have our app wired up with Redux, we'll create a ContactList component that's going to list all of the contacts registered to our app.

We're not going to set up database persistence yet.

Creating a Redux stateful component

Since our new component is stateful, meaning that it will have to listen to our Redux state to fetch the contacts, we need to wire it to Redux somehow. react-redux makes it easy, however, providing us with a connect function that wires up the state to our component by passing it via props. This means that we're going to access the Redux state in our component via this.props.

For the purposes of this guide, we're going to place our stateful components in a containers folder and our presentational (stateless) components in a components folder.

mkdir src/containers
nano src/containers/ContactList.js
import React, { Component } from 'react';

class ContactList extends Component {
  render() {

  }
}

export default ContactList;

In order to make the app state available to our component, we need to wrap it with a function call to connect, one of the functions available in the react-redux library. connect returns a function, that we will immediately call passing as its argument our new component.

import React, { Component } from 'react';
import { connect } from 'react-redux';

class ContactList extends Component {
  render() {

  }
}

export default connect()(ContactList);

This connect function will take two arguments: a function defining how the component will see the state, and one defining how it will call the actions, or, more precisely, dispatch them to the reducers. We will call these functions mapStateToProps and mapDispatchToProps, respectively.

Since we won't need to deal with dispatching actions yet, we will have mapDispatchToProps return an empty object, but we will return to it later on. Let's implement our mapStateToProps function now.

import React, { Component } from 'react';
import { connect } from 'react-redux';

class ContactList extends Component {
  render() {

  }
}

const mapStateToProps = state => ({
  ...state.contacts
});

const mapDispatchToProps = dispatch => ({});

export default connect(mapStateToProps, mapDispatchToProps)(ContactList);

Now our component has access to both contactList and loading keys through this.props.

Let's present something in our component, then. For now, we're not going to deal with the loading prop yet.

import React, { Component } from 'react';
import { connect } from 'react-redux';

class ContactList extends Component {
  render() {
    return (
      <div>
        <h1>Contacts</h1>
        <table className="table table-striped table-responsive">
          <thead>
            <tr>
              <th>Name</th>
              <th>Phone</th>
              <th>Email</th>
            </tr>
          </thead>
          <tbody>
            {
              this.props.contactList.map(({ name, phone, email }, index) => (
                  <tr key={index}>
                    <td>{name}</td>
                    <td>{phone}</td>
                    <td>{email}</td>
                  </tr>
              ))
            }
          </tbody>
        </table>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  ...state.contacts
});

const mapDispatchToProps = dispatch => ({});

export default connect(mapStateToProps, mapDispatchToProps)(ContactList);

When we're iterating over an array and we render multiple components as a result of that loop, we need to include a key prop to the highest-order component being returned so React can keep track of each component being rendered. Not including the key prop will raise an error.

Now let's render ContactList in our App component.

nano src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import ContactList from './containers/ContactList';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Contact List</h2>
        </div>
        <div className="App-intro">
          <ContactList />
        </div>
      </div>
    );
  }
}

export default App;

Since our contactList is still empty, this component won't show anything.

Commit the changes, then head to the next step.

git add .
git commit -m "Create ContactList component"

Next step: Add Bootstrap

Tidbit

{ ...var } is object spreading notation from ES7 that means "associate all keys and values to this new object". It's basically a shorthand to Object.assign({}, var).

This means that, in our mapStateToProps, we're returning a new object containing all the keys and values from the state.contacts object. Reminding that the state argument passed to mapStateToProps is the global application state.

Clone this wiki locally