Using Immutability Helpers for Redux reducers

← back to the blog

Immutability is a core concept of libraries like Redux, and has many advantages - not the least of which is that is easier to decide when a React component should update. The downside of immutability is that it's hard to do: familiar methods like .push modify arrays in place instead of producing and new ones, and even when trying to "think immutable" it's easy to mess up and modify and existing data structure.

There are several great solutions to this, the most well-known of which is Immutable.js. One which has been largely overlooked in the Immutability helper, formerly part of React but now seems to be maintained separately.

See the Github repo for a full explanation. Basically, you can "drill into" a deep data structure, modify the part you want using a special "command" object, and then get a brand, shiny new object at the end of it all.

To illustrate how it can work with Redux, I've modified the code example here:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return update(state, {
        visibilityFilter: {$set: action.filter}
      })      
    case ADD_TODO:
      return update(state, {
         todos: {$push: [{text: action.text, completed: false}]}
      })
    case TOGGLE_TODO:
      const todo = state.todos[action.index]
      const newTodo = update(todo, {
        completed: {$set: !todo.completed}
      })
      return update(state, {
        todos: {$splice: [[index, 1, newTodo]]}
      })
    default:
      return state
  }
}

What about Deep Freeze?

Personally, I like using Deep Freeze in test code, on the state which are about to pass through reducers. If we're ensuring the state isn't modified in tests, there's no need to include in the application code itself.