How to create a Redux reducer by convention

Cristian Salcescu
Feb 12 · 4 min read

Check my Discover Functional JavaScript and Functional React books.

Photo by Sergiu Vălenaș on Unsplash

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.

Reducer

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

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

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.

redux-points

{
  remove_todo : "remove_todo",
  reset_todos: "reset_todos",
  add_todo: "add_todo"
}

I would like to use a utility function to create both the reducer and the action types. Here is how the code may look like:

const { reducer, actionTypes } = createReducerAndActionTypes(
  { remove_todo, reset_todos, add_todo },
  []
);export default reducer;
export { actionTypes };

redux-points is a micro npm library created for this purpose. Here are the functions available:

createReducer(): creates the reducer by taking in an object with all setter functions and the initial state.

createActionTypes(): creates the action types by taking in an object with all setter functions.

createReducerAndActionTypes(): creates both the reducer and the action types by convention. It takes in all setter functions and the initial state.

Once created, the reducers and all available action types can be exported. Let’s use the action types in action creators.

import { actionTypes } from "../store/todos";const { reset_todos, remove_todo, add_todo } = actionTypes;function resetTodos(todos) {
  return {
    type: reset_todos,
    todos
  };
}function addTodo(todo) {
  return {
    type: add_todo,
    todo
  };
}function removeTodo(todo) {
  return {
    type: remove_todo,
    todo
  };
}export { resetTodos, addTodo, removeTodo };

Conclusion

The reducer function can be created by convention. redux-actions can be used for this purpose.

Try the redux-points npm package to split the reducer into small pure functions with names matching the action types. Combine the small pure functions to create the original reducer and the associated action types.

Here is the sample code on codesandbox.

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

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

Learn how to apply the Principles of Design Patterns.

You can find me on Twitter.

Cristian Salcescu

Written by

Author of Discover Functional JavaScript and Functional React. Enthusiastic about sharing ideas.