Spec-Zone.ru › Redux 3

Использование combineReducers

Основные понятия

Наиболее распространённая структура состояния для приложения Redux — это обычный JavaScript-объект, содержащий «слайсы» данных, относящихся к определённой области, под каждым ключом верхнего уровня. Аналогично, наиболее распространённый подход к написанию логики редьюсера для такой структуры состояния — это использование функций «слайс-редусеров», каждая с той же (state, action) сигнатурой, и каждая из них отвечает за управление всеми обновлениями этого конкретного слайса состояния. Несколько слайс-редусеров могут реагировать на одно и то же действие, независимо обновлять свой собственный слайс по мере необходимости, и обновлённые слайсы объединяются в новый объект состояния.

Поскольку этот шаблон очень распространён, Redux предоставляет combineReducers утилиту для реализации этого поведения. Это пример редусера высшего порядка, который принимает объект со слайс-редусер-функциями и возвращает новую функцию редусера.

Существует несколько важных моментов, которые следует учитывать при использовании combineReducers:

  • Прежде всего, combineReducers — это просто утилита для упрощения наиболее распространённого случая при написании редусеров Redux. Вы не обязаны использовать её в своём приложении, и она не обрабатывает все возможные сценарии. Совершенно возможно написать логику редусера без её использования, и часто требуется написать пользовательскую логику редусера для случаев, которые combineReducer не обрабатывает. (См. За пределами combineReducers для примеров и предложений.)
  • Хотя сам Redux не навязывает мнения о том, как организовано ваше состояние, combineReducers накладывает несколько правил, чтобы помочь пользователям избежать распространённых ошибок. (См. combineReducers для получения подробностей.)
  • Часто задаваемый вопрос заключается в том, «вызывает ли Redux все редусеры» при отправке действия. Поскольку на самом деле существует только одна корневая функция редусера, ответ по умолчанию — «нет, не вызывает» . Однако, combineReducers имеет специфическое поведение, которое действительно работает таким образом. Для сборки нового дерева состояния combineReducers будет вызывать каждый слайс-редусер с его текущим слайсом состояния и текущим действием, давая слайс-редусеру возможность отреагировать и обновить свой слайс состояния при необходимости. Итак, в этом смысле использование combineReducers действительно «вызывает все редусеры», или, по крайней мере, все слайс-редусеры, которые он оборачивает.
  • Вы можете использовать его на всех уровнях вашей структуры редусера, а не только для создания корневого редусера. Очень распространённо иметь несколько объединённых редусеров в различных местах, которые комбинируются для создания корневого редусера.

Определение формы состояния

Существует два способа определения начальной формы и содержимого состояния вашего хранилища. Во-первых, функция createStore может принимать preloadedState в качестве своего второго аргумента. Это в основном предназначено для инициализации хранилища состоянием, которое ранее сохранялось где-то ещё, например, в localStorage браузера. Другой способ — это корневой редусер, возвращающий начальное значение состояния, когда аргумент состояния undefined. Эти два подхода подробно описаны в Инициализация состояния, но есть некоторые дополнительные моменты, которые следует учитывать при использовании combineReducers.

combineReducers принимает объект со слайс-редусер-функциями и создаёт функцию, которая выводит соответствующий объект состояния с теми же ключами. Это означает, что если предопределённое состояние не предоставляется функции createStore, имена ключей в входном объекте слайс-редусеров определят имена ключей в выходном объекте состояния. Корреляция между этими именами не всегда очевидна, особенно при использовании функций ES6, таких как экспорт модулей по умолчанию и сокращения для объектов-литералов.

Вот пример того, как использование сокращений ES6 для литералов объектов с combineReducers может определить форму состояния:

// reducers.js
export default theDefaultReducer = (state = 0, action) => state;

export const firstNamedReducer = (state = 1, action) => state;

export const secondNamedReducer = (state = 2, action) => state;


// rootReducer.js
import {combineReducers, createStore} from "redux";

import theDefaultReducer, {firstNamedReducer, secondNamedReducer} from "./reducers";

// Use ES6 object literal shorthand syntax to define the object shape
const rootReducer = combineReducers({
    theDefaultReducer,
    firstNamedReducer,
    secondNamedReducer
});

const store = createStore(rootReducer);
console.log(store.getState());
// {theDefaultReducer : 0, firstNamedReducer : 1, secondNamedReducer : 2}

Обратите внимание, что поскольку мы использовали сокращения ES6 для определения литералов объектов, имена ключей в результирующем состоянии совпадают с именами переменных из импортов. Это может не всегда быть желаемым поведением и часто является причиной путаницы для тех, кто не так хорошо знаком с синтаксисом ES6.

Также результирующие имена немного странные. Как правило, не рекомендуется включать в имена ключей состояния слова, такие как «редусер» — ключи должны просто отражать область или тип данных, которые они хранят. Это означает, что мы должны либо явно указать имена ключей в объекте слайс-редусеров для определения ключей в выходном объекте состояния, либо тщательно переименовать переменные для импортированных слайс-редусеров, чтобы установить ключи при использовании сокращений для литералов объектов.

Более подходящий пример использования может выглядеть так:

import {combineReducers, createStore} from "redux";

// Rename the default import to whatever name we want. We can also rename a named import.
import defaultState, {firstNamedReducer, secondNamedReducer as secondState} from "./reducers";

const rootReducer = combineReducers({
    defaultState,                   // key name same as the carefully renamed default export
    firstState : firstNamedReducer, // specific key name instead of the variable name
    secondState,                    // key name same as the carefully renamed named export
});

const reducerInitializedStore = createStore(rootReducer);
console.log(reducerInitializedStore.getState());
// {defaultState : 0, firstState : 1, secondState : 2}

Эта форма состояния лучше отражает участвующие данные, потому что мы позаботились о настройке ключей, которые передали функции combineReducers.

© 2015–2017 Dan Abramov
Licensed under the MIT License.
http://redux.js.org/docs/recipes/reducers/UsingCombineReducers.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API