Перейти к основному содержимому
Неофициальный Бета-перевод

Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →

Базовая структура редьюсера и форма состояния

Базовая структура редьюсера

Прежде всего важно понять, что во всем вашем приложении фактически есть только одна функция-редьюсер: та, которую вы передали в createStore в качестве первого аргумента. Эта единственная функция-редьюсер должна выполнять несколько задач:

  • При первом вызове редьюсера значение state будет undefined. Редьюсер должен обработать этот случай, предоставив значение состояния по умолчанию до обработки входящего действия.

  • Ему необходимо проанализировать предыдущее состояние и диспетчеризованное действие, чтобы определить, какая работа требуется

  • При необходимости реальных изменений он должен создавать новые объекты и массивы с обновленными данными и возвращать их

  • Если изменения не требуются, следует вернуть существующее состояние как есть.

Самый простой подход к написанию логики редьюсера — объединить всё в одной функции:

function counter(state, action) {
if (typeof state === 'undefined') {
state = 0 // If state is undefined, initialize it with a default value
}

if (action.type === 'INCREMENT') {
return state + 1
} else if (action.type === 'DECREMENT') {
return state - 1
} else {
return state // In case an action is passed in we don't understand
}
}

Обратите внимание, что эта простая функция удовлетворяет всем базовым требованиям. Она возвращает значение по умолчанию при отсутствии состояния, инициализируя хранилище; определяет тип необходимого обновления на основе типа действия и возвращает новые значения; а также возвращает предыдущее состояние, если обновление не требуется.

В этот редьюсер можно внести простые улучшения. Во-первых, повторяющиеся конструкции if/else быстро становятся утомительными, поэтому обычно используют операторы switch. Во-вторых, для обработки начального случая "отсутствия данных" можно использовать значения параметров по умолчанию. С этими изменениями редьюсер будет выглядеть так:

function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}

Это базовая структура, характерная для типичной функции-редьюсера в Redux.

Базовая форма состояния

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

Состояние Redux обычно представляет собой простой JavaScript-объект на верхнем уровне дерева состояния. (Конечно, возможно использование других типов данных, например, числа, массива или специализированной структуры, но большинство библиотек предполагают, что верхнеуровневое значение — это простой объект.) Наиболее распространенный способ организации данных внутри этого объекта — разделение на поддеревья, где каждый верхнеуровневый ключ представляет некоторую "доменную" область или "срез" связанных данных. Например, состояние простого Todo-приложения может выглядеть так:

{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}

В этом примере todos и visibilityFilter являются верхнеуровневыми ключами состояния, каждый из которых представляет "срез" данных для определенной концепции.

Большинство приложений работают с несколькими типами данных, которые можно разделить на три категории:

  • Доменные данные: данные, которые приложению необходимо отображать, использовать или изменять (например, "все задачи Todo, полученные с сервера")

  • Состояние приложения: данные, специфичные для поведения приложения (например, "задача #5 выбрана" или "выполняется запрос на получение задач")

  • Состояние интерфейса: данные, отражающие текущее отображение UI (например, "диалоговое окно EditTodo открыто")

Поскольку хранилище представляет ядро вашего приложения, форму состояния следует определять в терминах доменных данных и состояния приложения, а не дерева UI-компонентов. Например, форма state.leftPane.todoList.todos была бы плохой идеей, поскольку концепция "todos" центральна для всего приложения, а не только для одной части интерфейса. Срез todos должен находиться на верхнем уровне дерева состояния.

Между структурой вашего UI и состоянием хранилища редко будет прямое соответствие 1:1. Исключение может составлять ситуация, когда вы явно отслеживаете различные аспекты UI-данных в Redux-хранилище. Но даже в этом случае структура UI-данных и доменных данных, скорее всего, будет различаться.

Типичная структура состояния приложения может выглядеть примерно так:

{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}