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

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

combineReducers(reducers)

Обзор

Функция-помощник combineReducers преобразует объект, содержащий различные функции "срезовых редьюсеров", в единый комбинированный редьюсер, который можно передать в configureStore из Redux Toolkit (или в устаревший метод createStore).

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

Совет

В большинстве случаев это не требуется — метод configureStore из Redux Toolkit автоматически вызовет combineReducers, если вы передадите объект срезовых редьюсеров:

const store = configureStore({
reducer: {
posts: postsReducer,
comments: commentsReducer
}
})

Вы всё ещё можете самостоятельно вызывать combineReducers(), если вам нужно вручную создать корневой редьюсер.

Срезы состояния

Состояние, создаваемое 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 }.

Аргументы

  1. reducers (Объект): Объект, значения которого соответствуют различным функциям редьюсеров, которые необходимо объединить в одну.
combineReducers({
posts: postsReducer,
comments: commentsReducer
})

Обратите внимание на правила, которым должен соответствовать каждый передаваемый редьюсер (см. ниже).

Возвращаемое значение

(Функция): Редьюсер, который вызывает каждый редьюсер внутри объекта reducers и формирует объект состояния с такой же структурой.

Примечания

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

Любой редьюсер, передаваемый в combineReducers, должен соответствовать следующим правилам:

  • Для любого нераспознанного действия должен возвращать полученное state (первый аргумент).

  • Никогда не должен возвращать undefined. Это слишком легко сделать случайно (например, через ранний return), поэтому combineReducers генерирует ошибку вместо того, чтобы позволить ей проявиться в другом месте.

  • Если полученное state равно undefined, должен возвращать начальное состояние для этого редьюсера. Согласно предыдущему правилу, начальное состояние также не должно быть undefined. Удобно задавать его через синтаксис параметров по умолчанию, но вы также можете явно проверить первый аргумент на 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 '@reduxjs/toolkit'
import todos from './todos'
import counter from './counter'

export default combineReducers({
todos,
counter
})

App.js

import { configureStore } from '@reduxjs/toolkit'
import reducer from './reducers/index'

const store = configureStore({
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 на любом уровне иерархии редюсеров. Это не обязательно должно происходить только на верхнем уровне. Фактически, вы можете повторно использовать его для разделения чрезмерно сложных дочерних редюсеров на независимые подчинённые редюсеры, и так далее.