combineReducers(reducers)
По мере усложнения приложения вам захочется разделить вашу функцию сведения на отдельные функции, каждая из которых будет управлять независимыми частями состояния.
Функция-помощник combineReducers преобразует объект, значениями которого являются различные функции сведения, в одну функцию сведения, которую можно передать в createStore.
Результат редьюсер вызовет каждый дочерний редьюсер и соберет их результаты в один объект состояния. Состояние, произведённое combineReducers() , размещает состояния каждого редьюсера под их ключами, как передано в combineReducers()
Пример:
rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer})
// This would produce the following state object
{
potato: {
// ... potatoes, and other state managed by the potatoReducer ...
},
tomato: {
// ... tomatoes, and other state managed by the tomatoReducer, maybe some nice sauce? ...
}
}Вы можете контролировать имена ключей состояния, используя разные ключи для редьюсеров в переданном объекте. Например, вы можете вызвать combineReducers({ todos: myTodosReducer, counter: myCounterReducer }) для того, чтобы форма состояния была { todos, counter }.
Распространённой практикой является именование редьюсеров по частям состояния, за которые они отвечают, поэтому вы можете использовать сокращённую запись свойств ES6: combineReducers({ counter, todos }). Это эквивалентно записи combineReducers({ counter: counter, todos: todos }).
Примечание для пользователей Flux
Эта функция помогает вам организовать свои редьюсеры для управления своими частями состояния, аналогично тому, как у вас были бы разные Flux Stores для управления разными состояниями. В Redux всего один магазин, но
combineReducersпомогает вам сохранить ту же логическую разделение между редьюсерами.
Аргументы
-
reducers(Объект): Объект, значениями которого являются различные функции сведения, которые нужно объединить в одну. Ниже приведены некоторые правила, которым должен соответствовать каждый переданный редьюсер.
В предыдущей документации предлагалось использовать синтаксис ES6
import * as reducersдля получения объекта редьюсеров. Это вызвало много путаницы, поэтому мы теперь рекомендуем экспортировать единственный редьюсер, полученный с помощьюcombineReducers()изreducers/index.jsвместо этого. Ниже приведён пример.
Возвращаемое значение
(Функция): Редьюсер, который вызывает каждый редьюсер внутри объекта reducers, и строит объект состояния с той же формой.
Примечания
Данная функция имеет некоторую предвзятость и склонна к тому, чтобы помочь начинающим избежать распространённых ошибок. Именно поэтому она пытается навязать некоторые правила, которых вам не обязательно придерживаться, если вы пишете корневой редьюсер вручную.
Любой редьюсер, переданный в combineReducers, должен удовлетворять этим правилам:
Для любого нераспознанного действия он должен возвращать
state, переданное ему в качестве первого аргумента.Он никогда не должен возвращать
undefined. Очень легко случайно сделать это с помощью раннего оператораreturn, поэтомуcombineReducersвыбрасывает исключение, если вы это сделаете, вместо того, чтобы позволить ошибке проявиться где-то ещё.Если
state, переданное ему, являетсяundefined, он должен вернуть начальное состояние для данного конкретного редьюсера. Согласно предыдущему правилу, начальное состояние также не должно бытьundefined. Удобно задать его с использованием синтаксиса ES6 необязательных аргументов, но можно также явным образом проверить первый аргумент на соответствиеundefined.
Хотя combineReducers пытается проверить, соответствуют ли ваши редьюсеры некоторым из этих правил, вам следует помнить о них и стараться придерживаться их. combineReducers будет проверять ваши редьюсеры, передавая им undefined; это делается даже если вы задаёте начальное состояние для Redux.createStore(combineReducers(...), initialState). Поэтому вы обязаны убедиться, что ваши редьюсеры работают правильно, когда получают undefined в качестве состояния, даже если вы никогда не намерены передавать им undefined в собственном коде.
Пример
reducers/todos.js
export default function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text])
default:
return state
}
}reducers/counter.js
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}reducers/index.js
import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'
export default combineReducers({
todos,
counter
})App.js
import { createStore } from 'redux'
import reducer from './reducers/index'
const store = createStore(reducer)
console.log(store.getState())
// {
// counter: 0,
// todos: []
// }
store.dispatch({
type: 'ADD_TODO',
text: 'Use Redux'
})
console.log(store.getState())
// {
// counter: 0,
// todos: [ 'Use Redux' ]
// }Советы
Эта вспомогательная функция просто удобство! Вы можете написать свой собственный
combineReducers, который работает по-другому, или даже собрать объект состояния из дочерних редьюсеров вручную и написать функцию корневого сведения явно, как вы бы писали любую другую функцию.Вы можете вызвать
combineReducersна любом уровне иерархии редьюсеров. Это не обязательно должно происходить на самом верху. На самом деле, вы можете использовать его снова, чтобы разделить дочерние редьюсеры, которые становятся слишком сложными, на независимых внуков, и так далее.
© 2015–2021 Dan Abramov
Licensed under the MIT License.
https://redux.js.org/api/combinereducers