Все, что хранится в хранилище, мы называем состоянием, но не все состояния одинаково полезны. Вот какую классификацию вводит документация Redux:
Так как стор представляет собой ядро приложения, данные внутри него должны описываться в терминах domain data и app state, но не как дерево компонентов UI. Например, такой способ формирования состояния state.leftPane.todoList.todos — плохая идея. Крайне редко дерево компонентов отражается напрямую на структуру состояния, и это нормально. Представление зависит от данных, а не данные от представления.
Типичная структура состояния выглядит так:
{
domainData1 : {}, // todos
domainData2 : {}, // comments
appState1 : {},
appState2 : {},
uiState1 : {},
uiState2 : {},
}
Как уже говорилось в курсе JS: React, структура состояния должна напоминать базу данных. Всё максимально плоско и нормализованно.
{
todos: [
{ id: 1, name: 'why?' },
{ id: 3, name: 'who?' },
],
comments: [
{ id: 23, todoId: 3, text: 'great!' },
],
}
С такой структурой крайне легко писать реакцию на действия, обновлять данные, добавлять новые и удалять старые. Вложенность небольшая, всё просто. Но появляется другая проблема (появляется она в любом случае). С ростом количества сущностей, редьюсер становится очень тяжёлым. Огромный кусок кода, который делает всё. Для решения этой проблемы, Redux имеет встроенный механизм, позволяющий создавать множественные редьюсеры и комбинировать их друг с другом. Работает это так: для каждого свойства верхнего уровня пишется свой собственный редьюсер, а затем они с помощью функции combineReducers()
объединяются в корневой (root) редьюсер, который уже используется для создания хранилища. Экшены попадают во все редьюсеры, собранные внутри combineReducers()
.
import { combineReducers, createStore } from 'redux';
const todosReducer = (state = [], action) => {
// сюда попадут данные из todos
};
const commentsReducer = (state = [], action) => {
// сюда попадут данные из comments
};
const rootReducer = combineReducers({
todos: todosReducer,
comments: commentsReducer,
});
const store = createStore(rootReducer);
// Если назвать редьюсеры как свойства в состоянии, то код можно сократить:
// const todos = (state = [], action) => { ... };
// const comments = (state = [], action) => { ... };
// const rootReducer = combineReducers({ todos, comments });
В каждый редьюсер приходит state, но это не всё состояние хранилища, а только та часть, которая лежит в соответствующем свойстве. Не забудьте про это.
Редьюсеры могут быть даже вложенными, и для этого не нужны никакие специальные средства, это обычные функции, принимающие на вход данные и возвращающие новые данные. С таким подходом появляется одна особенность, которая вначале может испугать. Так как каждый редьюсер имеет доступ только к своей части состояния, действия, порождающие изменения сразу в нескольких местах, будут повторяться в разных редьюсерах:
const todos = (state = {}, action) => {
switch (action.type) {
case 'TODO_REMOVE':
// ...
}
};
const comments = (state = {}, action) => {
switch (action.type) {
// При удалении ToDo нужно удалить все его комментарии
case 'TODO_REMOVE':
// ...
}
};
То есть правильный подход состоит в том, чтобы повторять часть case
в нужных редьюсерах, а не в том, чтобы пытаться получить недостающие части состояния.
Вам ответят команда поддержки Хекслета или другие студенты.
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Наши выпускники работают в компаниях:
Зарегистрируйтесь или войдите в свой аккаунт