combineReducers: merging slice reducers to create combined state">combineReducers: merging slice reducers to create combined state">
跳至主要內容

combineReducers(reducers)

概觀

combineReducers 輔助函式將值為不同「區塊 reducer」函式的物件轉換為單一的組合 reducer 函式,可傳遞至 Redux Toolkit 的 configureStore (或舊版的 createStore 方法)

產生的組合 reducer 會在每次發送動作時呼叫每個區塊 reducer,並將其結果收集到單一狀態物件中。這能將 reducer 邏輯拆分為獨立管理其自身狀態區塊的個別函式。

提示

這很少會用到 - 如果傳入區塊 reducer 物件,Redux Toolkit 的 configureStore 方法 會自動呼叫 combineReducers

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

如果你需要先手動建構根 reducer,仍然可以自己呼叫 combineReducers()

狀態切片

combineReducers() 所產生的狀態,會將每個 reducer 的狀態命名空間化,其鍵值與傳遞給 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? ...
}
}

你可以透過傳遞物件中不同 reducer 的不同鍵值來控制狀態鍵值的名稱。例如,你可以呼叫 combineReducers({ todos: myTodosReducer, counter: myCounterReducer }),讓狀態形狀變成 { todos, counter }

參數

  1. reducers (物件):一個物件,其值對應至需要合併成一個的各個 reducer 函式。
combineReducers({
posts: postsReducer,
comments: commentsReducer
})

請參閱下方的注意事項,了解每個傳遞的 reducer 都必須遵循的一些規則。

傳回

(函式):一個 reducer,會呼叫 reducers 物件中的每個 reducer,並建構一個具有相同形狀的狀態物件。

注意事項

此函式稍微有點主觀,而且偏向於幫助初學者避免常見的陷阱。這就是為什麼它會嘗試強制執行一些規則,如果你手動撰寫根 reducer,則不必遵循這些規則。

傳遞給 combineReducers 的任何 reducer 都必須符合這些規則

  • 對於任何無法辨識的動作,它都必須傳回給定給它的 state 作為第一個參數。

  • 它絕不能傳回 undefined。透過提早 return 陳述式來執行此動作太容易出錯,因此如果你這樣做,combineReducers 會擲回錯誤,而不是讓錯誤在其他地方顯現。

  • 如果給定的 stateundefined,它必須傳回此特定 reducer 的初始狀態。根據前一個規則,初始狀態也不得為 undefined。使用可選參數語法指定初始狀態很方便,但你也可以明確檢查第一個參數是否為 undefined

雖然 combineReducers 會嘗試檢查你的 reducer 是否符合這些規則中的一些,但你應該記住這些規則,並盡力遵循它們。combineReducers 會透過傳遞 undefined 給你的 reducer 來檢查你的 reducer;即使你為 Redux.createStore(combineReducers(...), initialState) 指定初始狀態,它也會執行此動作。因此,你必須確保你的 reducer 在接收 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,它運作方式不同,甚至可以手動從子 reducer 組合狀態物件,並明確撰寫根 reducer 函式,就像撰寫任何其他函式一樣。

  • 您可以在 reducer 層級的任何層級呼叫 combineReducers。它不一定要發生在最頂層。事實上,您可能會再次使用它,將過於複雜的子 reducer 分割成獨立的孫 reducer,以此類推。