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.