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 }
。
參數
reducers
(物件):一個物件,其值對應至需要合併成一個的各個 reducer 函式。
combineReducers({
posts: postsReducer,
comments: commentsReducer
})
請參閱下方的注意事項,了解每個傳遞的 reducer 都必須遵循的一些規則。
傳回
(函式):一個 reducer,會呼叫 reducers
物件中的每個 reducer,並建構一個具有相同形狀的狀態物件。
注意事項
此函式稍微有點主觀,而且偏向於幫助初學者避免常見的陷阱。這就是為什麼它會嘗試強制執行一些規則,如果你手動撰寫根 reducer,則不必遵循這些規則。
傳遞給 combineReducers
的任何 reducer 都必須符合這些規則
對於任何無法辨識的動作,它都必須傳回給定給它的
state
作為第一個參數。它絕不能傳回
undefined
。透過提早return
陳述式來執行此動作太容易出錯,因此如果你這樣做,combineReducers
會擲回錯誤,而不是讓錯誤在其他地方顯現。如果給定的
state
是undefined
,它必須傳回此特定 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,以此類推。