React + Redux Tutorial Part IV: The Index Feature

The Index Feature: Building the CatsPage Component


This is Part IV 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


In this section, we'll define our component, connect it to the store, and teach it how to receive state from the store and utilize aspects of that state as props.

We'll define our component in src/components/cats/CatPage.js.

import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import * as catActions from '../../actions/catActions';

class CatPage extends React.Component {
  render() {
    return()
  }
}


CatPage.propTypes = {
 
};

function mapStateToProps(state, ownProps) {

} 
   
export default connect(mapStateToProps)(CatPage);

Our empty component has a few key features. Let's take a closer look.

The connect function

The connect function is provided by Redux. It subscribes our container component to the store, so that it will be alerted when state changes.

Not every component will be connected, or subscribed, to the store. Only container, or "stateful", components will be connected to the store.

Container vs. Presentational Components

A container component is a component that is connected to the store and aware of application state and changes to that state. It takes that state and passes aspects of it to presentational components as props.

Container components have functions that dispatch actions that enact our earlier flow of action dispatch -> API call -> action dispatch -> store -> reducer -> component re-render. Container components will pass such functions into presentational components as props.

Presentational components are not aware of the store or our application state. They know about their own props. They respond to user actions by invoking callback functions that their container component passed them.

These differences will become clearer when we build out our create, edit and delete cat features.

For now, check out this excellent table from the Redux docs

Now, back to our CatsPage component.

The mapStateToProps Function

Our connect function takes in an argument: mapStateToProps, which is a function.

The mapStateToProps function has a very important job: receive application state from the store whenever state has changed and make data from that data available to the component as props.

Our CatsPage component needs to display all of the cats, so our mapStateToProps function should grab the cats from state. Let's do it!

function mapStateToProps(state, ownProps) {
  // state = {cats: [{id:1, name: "Maru"}, etc.]}
  return {
    cats: state.cats
  };
}

Our function should return a new object, the key/value pairs of which will become available as props and their values in our component.

Next up, we want to add some Prop Type validation to our component.

Prop Type Validation

We want to ensure that the cats property of our component is in fact in array. We should also require that our component receive this property, otherwise it will have nothing to render.

CatsPage.propTypes = {
  cats: PropTypes.array.isRequired
};

Now, we're ready to render!

The render() function

We've already discussed container vs. presentational components and we've come to understand that container components are responsible for how things work--getting data from the store and formatting it, for example.

Presentational components, on the other hand, are in charge of how things look.

So, let's let our container component be a container component. We'll have it render a presentational component to format and display our list of cats.

We'll build a CatList component for the CatPage component to render.

src/components/cats/CatPage.js
import CatList from './CatList';

...

class CatsPage extends React.Component {
  render() {
    return (
      <div className="col-md-12">
        <h1>Cats</h1>
        <div className="col-md-4">
          <CatList cats={this.props.cats} />
        </div>
      </div>
    );
  }
}

Our container component is passing the cats collection that it took from state, down to our presentational component, CatList.

Let's go ahead and define our presentational component.

The CatList Component: A Functional Component

We'll define our CatList component as a functional component. React allows us to define components as classes, which is what we've seen so far, or as functions.

For small, stateless (i.e. presentation) components, function definitions provide a clean, eloquent interface.

Functional components take in an argument of props, which are passed in when the component is called. Functional components don't have an explicit render method, instead they render whatever is returned. For more on functional components, check out this Medium post by Cory House.

We'll define our CatList component as a functional component, and have it accept an argument of cats, passed in as a prop when the component is called from the CatsPage component.

Our component is simple, it validates the cats Prop Type, and iterates over cats to form a collection of, and render, list items that wrap each cat's name.

React Elements and the key Property

Notice that we are assigning a unique key property to each list item. React elements that are iteratively constructed, or part of an array, should each receive a unique key property. React will use this information to efficiently re-render the smallest possible portion of the DOM. For more on how React uses element keys to do this, check out this post.

import React, {PropTypes} from 'react';

const CatList = ({cats}) => {
  return (
      <ul className="list-group">
        {cats.map(cat => 
          <li className="list-group-item" key={cat.id}>
            {cat.name}
          </li>
        )}
      </ul>
  );
};

CatList.propTypes = {
  cats: PropTypes.array.isRequired
};

export default CatList;

Now, our app should successfully load all the cats from the API, pass them down to the CatsPage container component, which renders them with the help of the CatList presentational component.

We're ready to build out the individual cat show page!

Part V: The Show Feature >>

subscribe and never miss a post!

Blog Logo

Sophie DeBenedetto

comments powered by Disqus
comments powered by Disqus