上次更新: 2024-06-06
在講解 Redux-toolkit 的 Extra reducers 之前,有個觀念必須先理解。
在純 Redux 中,當我們發送 action (dispatch action) 時,reducer 會依照 action 做相關的處理,這我們已非常清楚。
只是我們可能會漏掉一個觀念:其實所有的 reducer 都會接收到這個 action,但只有相關的 reducer 會做處理,其他的無關的 reducer 則會忽略這個 action。
而在 Redux-toolkit 中則不是這樣,reducer 只會接收到它的 slice 所產生的 action。
Demo: https://codesandbox.io/p/sandbox/redux-9-redux-reducer-additional-g5g7rz
我們先來使用之前純 Redux 的範例做說明,以下是部份的程式碼:
// cake reducer
const cakeReducer = (prevState = cakeState, action) => {
switch (action.type) {
case 'CAKE_ORDER':
const cakeQuantity = action.payload.quantity;
return {
...prevState,
cakes: prevState.cakes - cakeQuantity,
};
default:
return prevState;
}
};
// ice cream reducer
const iceCreamReducer = (prevState = iceCreamState, action) => {
switch (action.type) {
case 'ICECREAM_ORDER':
const iceCreamQuantity = action.payload.quantity;
return {
...prevState,
iceCream: prevState.iceCream - iceCreamQuantity,
};
default:
return prevState;
}
};以同樣蛋糕店的例子來做說明,假如現在有促銷活動,只要買蛋糕,就會送一個冰淇淋。要怎麼做呢?
我們在 iceCreamReducer 裡再加上 CAKE_ORDER,這樣當下單蛋糕時 action type 符合,就會觸發將 iceCream 減一。
// ice cream reducer
const iceCreamReducer = (prevState = iceCreamState, action) => {
switch (action.type) {
case 'ICECREAM_ORDER':
const iceCreamQuantity = action.payload.quantity;
return {
...prevState,
iceCream: prevState.iceCream - iceCreamQuantity,
};
// 多加了 CAKE_ORDER
case 'CAKE_ORDER':
return {
...prevState,
iceCream: prevState.iceCream - 1,
};
default:
return prevState;
}
};可以看到當發送 action,type 為 CAKE_ORDER 時,cake 跟 iceCream 數量都減一了!

Redux , 在 Redux-toolkit 中 reducer 只會接收到它的 slice 所產生的 action。slice 的 action,就需要用到 Extra Reducers。createSlice 以外,額外產生的 reducer。Demo: https://codesandbox.io/p/devbox/redux-9-redux-toolkit-extra-reducers-lhjytq
同樣的例子,我們要在蛋糕下單時,送一個冰淇淋。
也就是說,在 action type 為 cake/order 時,冰淇淋數量要減一。
要怎麼設定呢?
在 createSlice 中加上 extraReducers 屬性,可以有兩種寫法。
// features/iceCream/iceCreamSlice.js
const iceCreamSlice = createSlice({
name: 'iceCream',
initialState: {
numOfIceCream: 10,
},
reducers: {
order: (state, action) => {
state.numOfIceCream -= action.payload.quantity;
},
restock: (state, action) => {
state.numOfIceCream += action.payload.quantity;
},
},
// 寫法一
extraReducers: {
['cake/order']: (state, action) => {
state.numOfIceCream--;
},
},
// 寫法一
extraReducers: (builder) => {
builder.addCase(cakeActions.order, (state, action) => {
state.numOfIceCream--;
});
},
});extraReducer 的值會是一個物件
action type使用 build function,這是比較建議的寫法,寫法如下
extraReducers 的值會是一個函式
builder 參數builder 來新增一個情況,語法為 builder.addCase()addCase 中傳入兩個參數,第一個是 action type,這邊的 action type 我們使用 redux-toolkit 自動幫我們產生好的 action,因此使用 cakeActions.orderaddCase 的第二個是函式,同寫法一的函式,我們把要做的相應處理定義在這邊cake/order 減一參考資料: