A Beginner’s Guide to Redux (part 3)

Welcome to part 3 in my beginner’s guide to Redux!

In part one we covered the basics of implementing Redux in a React application, and in part two we added some more advanced features.

The last thing I do want to touch on is the second argument we can pass into the connect function, mapDispatchToProps. If you remember in our Counter component, we sent the dispatch off by dispatching a function on button click, which then called props.dispatch(actionCreatorFunction()):

// src/components/Counter.js

// [...]

const Counter =  (props) => {
  return (
    <div>
      <h3>Current count: {props.count}</h3>
      <button onClick={() => props.dispatch(incrementCount())}>Increment</button>
      <button onClick={() => props.dispatch(decrementCount())}>Decrement</button>
      <button onClick={() => props.dispatch(resetCount())}>Reset</button>
    </div>
  );
}

// [...]

This technically works, but as our dispatches get more complex and we’re dealing with larger data sets things can get real messy, real quick. Additionally, this goes against a core principle of computer science, which is the “separation of concerns”.

In this instance, our Counter component is providing the user with an interface through which they can affect the data within the application. It also displays that data for the user to view. However, inside the counter component is also the logic that sends the data to the store.

We previously separated the logic that fetches the data from the store with the mapStateToProps function; the mapDispatch to props will help us separate this other set of concerns.

The mapDispatchToProps function is similar to the mapStateToProps function, in that it’s goal is to return an object which maps all of the dispatch functions onto the local props of the component in question. As such, the basic building blocks of the code don’t look all the different:

const mapStateToProps = (state) => ({
  count: state.count
})

const mapDispatchToProps = (dispatch) => ({
  increment: // function goes here,
  decrement: // function goes here,
  reset: // function goes here
})

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

We finish by adding mapDispatchToProps in as the second argument to the connect function. From here, we simply take the code that sits inside the onClick functions of the buttons:

<button onClick={() => props.dispatch(incrementCount())}>Increment</button>
<button onClick={() => props.dispatch(decrementCount())}>Decrement</button>
<button onClick={() => props.dispatch(resetCount())}>Reset</button>

And move it down into the mapDispatchToProps function:

const mapDispatchToProps = (dispatch) => ({
  increment: () => dispatch(incrementCount()),
  decrement: () => dispatch(decrementCount()),
  reset: () => dispatch(resetCount())
})

(Since dispatch is available on the mapDispatchToProps function, we don’t need to access it through the props.)

Now that that’s done these functions have been mapped to the local props of the component, and can be accessed directly from there:

const Counter =  (props) => {
  return (
    <div>
      <h3>Current count: {props.count.count}</h3>
      <button onClick={props.increment}>Increment</button>
      <button onClick={props.decrement}>Decrement</button>
      <button onClick={props.reset}>Reset</button>
    </div>
  );
}

We can even use some ES6 destructuring to access them directly in the arguments of the Counter component, and clean the code up a bit further:

const Counter =  ({ count, increment, decrement, reset }) => {
  return (
    <div>
      <h3>Current count: {count.count}</h3>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

And there we have it! All the logic associated with sending data to and fetching data from the Redux store has been separated from the Counter component, which now has the sole responsibility of displaying the data and inputs to the user.

There are some other features of Redux I could dive into, but I think this is a good stopping point. If we’re going to take an 80/20 approach to learning how to use different coding tools, I think everything covered in this series so far gives us the 20% needed to use Redux to 80% of it’s capabilities.

Once I’ve played around with Redux more in building actual applications and have dabbled with those other features, I’ll probably write parts 4 onward to cover those additional features.

But that’s it for now, til next time!

-Brandon