Redux - очень популярная библиотека управления состоянием. Он упрощает исходную архитектуру Flux, объединяя все хранилища и диспетчер в одном объекте хранилища.

Redux продвигает использование функционального программирования для управления состоянием. Он вводит понятие функции редуктора.

Редуктор

Редуктор - это чистая функция, которая принимает состояние и действие в качестве параметров и возвращает новое состояние.

Может быть много редукторов, управляющих частями корневого состояния. Мы можем объединить их вместе с combineReducers() служебной функцией и создать корневой редуктор.

Вот как может выглядеть редуктор todos:

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;

state в данном случае - это список дел. Мы можем применить к его действиям, например, add_todo, remove_todo, reset_todos.

Редуктор по соглашению

Я хотел бы избавиться от оператора switch в редукторе. Функции должны быть небольшими и делать одно.

Давайте разделим редуктор на небольшие чистые функции с именами, соответствующими типам действий. Я назову эти сеттер-функции. Каждый из них принимает состояние и действие в качестве параметров и возвращает новое состояние.

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]);
}

редукс-действия

Я хотел бы объединить все эти небольшие функции вместе, чтобы создать исходную функцию-редуктор. Для этого мы можем использовать служебную функцию handleActions() из redux-actions.

import { handleActions } from "redux-actions";
const reducer = handleActions(
  { remove_todo, reset_todos, add_todo },
  []
);
export default reducer;

Функции установщика будут выполняться по соглашению. Когда поступает действие с типом remove_todo, будет выполнена функция установки remove_todo().

редукционные точки

На этом этапе я хотел бы создать типы действий на основе имен функций установщика. Вот как может выглядеть объект со всеми типами действий:

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

Я хотел бы использовать служебную функцию для создания как редуктора, так и типов действий. Вот как может выглядеть код:

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

Redux-points - это созданная для этого микро-библиотека npm. Вот доступные функции:

createReducer(): создает редуктор, принимая объект со всеми функциями сеттера и начальным состоянием.

createActionTypes(): создает типы действий, принимая объект со всеми функциями установщика.

createReducerAndActionTypes(): по соглашению создает и редуктор, и типы действий. Он принимает все функции установки и начальное состояние.

После создания редукторы и все доступные типы действий могут быть экспортированы. Давайте использовать типы действий в создателях действий.

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 };

Заключение

Редуктор - это чистая функция, которая принимает состояние и действие и возвращает новое состояние.

Функция редуктора может быть создана по соглашению. redux-actions можно использовать для этой цели.

Попробуйте пакет npm redux-points, чтобы разделить редуктор на небольшие чистые функции с именами, соответствующими типам действий. Объедините небольшие чистые функции, чтобы создать исходный редуктор и связанные с ним типы действий.

Вот пример кода на codeandbox.