Discover Functional JavaScript was named one of the best new Functional Programming books by BookAuthority!

Redux is a very popular state management library. It simplifies the original Flux architecture by combining all stores and the dispatcher in a single store object.

Redux promotes the use of functional programming for managing state. It introduces the reducer function concept.

Data flow

Let’s look at the data flow inside the Redux store.

An action is a plain object that contains all information necessary to do that action.

An action creator is a function that creates an action object.

Reducer

A reducer is a pure function that takes state and action as parameters and returns the new state.

There may be many reducers managing parts of the root state. We can combine them together with combineReducers() utility function and create the root reducer.

Here is how the todos reducer may look like:

import matchesProperty from "lodash/matchesProperty";
function todos(todos = [], action) {
 switch (action.type) {
  case "add_todo":
    const id = getMaxId(todos) + 1;
    const newTodo = { ...action.todo, id };
    return todos.concat([newTodo]);
  case "remove_todo":
    const index = todos.findIndex(matchesProperty("id",
                                  action.todo.id));
    return [...todos.slice(0, index), ...todos.slice(index + 1)];
  case "reset_todos":
    return action.todos;
  default:
    return state;
  }
}
export default todos;

The state in this case is the list of to-dos. We can apply to its actions like add_todo, remove_todo, reset_todos.

Reducer by convention

I would like to get rid of the switch statement in the reducer. Functions should be small and do one thing.

Let’s split the reducer into small pure functions with names matching the action types. I will call these setter functions. Each of them takes state and action as parameters and returns the new state.

function remove_todo(todos, action) {
  const index = todos.findIndex(matchesProperty("id",
                                action.todo.id));
  return [...todos.slice(0, index), ...todos.slice(index + 1)];
}

function reset_todos(todos, action) {
  return action.todos;
}

function add_todo(todos, action) {
  const id = getMaxId(todos) + 1;
  const newTodo = { ...action.todo, id};
  return todos.concat([newTodo]);
}

redux-actions

I would like to combine all these small functions together to create the original reducer function. We can use the handleActions() utility function from redux-actions for this.

import { handleActions } from "redux-actions";

const reducer = handleActions(
  { remove_todo, reset_todos, add_todo },
  []
);

export default reducer;

The setter functions will run by convention. When an action with type remove_todo comes in, the remove_todo() setter function will be executed.

Here is the sample code on codesandbox.

Discover Functional JavaScript was named one of the best new Functional Programming books by BookAuthority!

For more on applying functional programming techniques in React take a look at Functional React.

Learn functional React, in a project-based way, with Functional Architecture with React and Redux.

Follow on Twitter