Refactoring to the Reducer Pattern

Let's start refactoring to the reducer pattern in this lesson.

We'll cover the following

Current issues

While there’s a lot to like about the previous solution, it has a couple of issues that, while not necessarily a problem at this size, might become a problem if the code gets more complex. For example:

  • Each individual action needs to know to call calendarFilterChanged to trigger a refresh.
  • The actual state is global and mutable, which means if some piece of code grabs the data and starts writing it, that change is made to everybody else, whether we want it to or not.

Refactoring

In order to prevent these problems, we’re going to refactor this central data using a common JavaScript pattern called a reducer and a related structure called a store.

A reducer is a JavaScript function that takes two arguments. The first argument is an object representing a state. The second argument represents an action to take. The return value is a new state object representing the state of the data after the action is performed. The action is meant to describe the state change in terms of application logic, while the reducer converts that to changes in data.

Let’s look at a simple example, in which we will count American coins. The state of the world is the number of coins and the total value of the coins. A reducer to partially handle this task might look like this (we’ll talk about TypeScript annotations to this in a moment):

const initialState = {count: 0, value: 0}

const reducer = (state, action) {
  switch (action.type) {
	  case "AddPenny": {
	    return { count: state.count + 1, value: state.value + 1 }
    }
    case "AddNickel": {
	    return { count: state.count + 1, value: state.value + 5 }
    } 
    // and so on...
  }
}   

Then, you’d call this method with something like:

const withAPenny = reducer(initialState, {type: "AddPenny"}) 
const pennyAndNickel = reducer(withAPenny, {type: "AddNickel"})

The idea is that you only change the state via the reducer function. Each call to the reducer function returns a new instance of the state object that is separate from all of the other instances.

This is somewhat more verbose than, you know, not doing this kind of change as a reducer, which obviously raises the question of why use this structure at all? To be perfectly honest, this is a case where my own taste in software structures clashes a little bit. I find this pattern, as typically implemented in JavaScript, to be a little verbose.

That said, the basic idea of making the central state immutable and only accessible via specific methods is still a good one, and we’ll stick with talking about the pattern, as you are most likely to see it in other JavaScript code.

Get hands-on with 1200+ tech skills courses.