前一篇我們了解了 extraReducer 的用法,並完成了咖啡商品的 slice 和 assetsSlice 裏面設定 extraReducer 綁定 coffee/coffeeOrdered 的動作,完成資金的加減。
同樣的原理,我們今天來處理另外一樣商品咖啡豆。
首先我們先回到 ./index.js,將用不到的指令先碼掉,並與原本咖啡的作法類似,重新定義我們要帶入參數的格式,如下:
// ./index.js
const { store } = require('./features/store');
const coffeeActions = require('./features/slices/coffeeSlice').coffeeActions;
const coffeeBeanActions = require('./features/slices/coffeeBeanSlice').coffeeBeanActions;
const cakeActions = require('./features/slices/cakeSlice').cakeActions;
console.log('Initial State', store.getState());
const unsubscribe = store.subscribe(() => console.log('更新', store.getState()));
// store.dispatch(coffeeActions.coffeeOrdered({qty: 1, money: 10}));
// store.dispatch(coffeeActions.coffeeOrdered({qty: 4, money: 40}));
// store.dispatch(coffeeActions.coffeeRestocked({qty: 10, money: 20}));
store.dispatch(coffeeBeanActions.coffeeBeanOrdered({qty: 2, money: 10}));
store.dispatch(coffeeBeanActions.coffeeBeanRestocked({qty: 5, money: 5}));
// store.dispatch(cakeActions.cakeOrdered(3));
// store.dispatch(cakeActions.cakeRestocked(6));
unsubscribe();
格式上我們簡單改為 qty 計入數量、money 計入錢,這樣統一模組不再是以 pay & income 來處理也比較容易直觀地使用,送入之後再交由 reducers 來決定對錢與數量的增減,這裡也體現了程式設計的複用性。
接著我們回到 coffeeBeanSlice 裏面做以下修改:
// features/slices/coffeeBeanSlice.js
const { createSlice } = require("@reduxjs/toolkit");
// only 的 coffeeBean
const initialState = {
numOfCoffeeBean: 20
}
const coffeeBeanSlice = createSlice({
name: 'coffeeBean',
initialState,
reducers: {
// 是 qty, 我加了 qty
coffeeBeanOrdered: (state, action) => {
state.numOfCoffeeBean = state.numOfCoffeeBean - action.payload.qty
return state;
},
coffeeBeanRestocked: (state, action) => {
// 是 qty, 我加了 qty
state.numOfCoffeeBean = state.numOfCoffeeBean + action.payload.qty
return state;
},
}
})
module.exports = coffeeBeanSlice.reducer;
module.exports.coffeeBeanActions = coffeeBeanSlice.actions;
接著我們到 assetsSlice 來修正我們的 extraReducer,新增剛剛 coffeeBeanSlice 的 actions:
// features/slices/assetsSlice.js
const { createSlice } = require("@reduxjs/toolkit");
const { coffeeOrdered, coffeeRestocked } = require('./coffeeSlice').coffeeActions;
const { coffeeBeanOrdered, coffeeBeanRestocked } = require('./coffeeBeanSlice').coffeeBeanActions;
// only assetsReducer
const initialState = {
money: 1000,
}
const assetsSlice = createSlice({
name: 'assets',
initialState,
reducers: {},
// 這個是讓其他的slice reducer function來影響這裡的state,以下為兩種不同的寫法。
// extraReducers: {
// ['coffee/coffeeOrdered']: (state, action) => {
// state.money = state.money + action.payload.money
// return state;
// },
// ['coffee/coffeeRestocked']: (state, action) => {
// state.money = state.money - action.payload.money
// return state;
// },
// }
extraReducers: (builder) => {
builder
.addCase(coffeeOrdered, (state, action) => {
state.money = state.money + action.payload.money
return state;
})
.addCase(coffeeRestocked, (state, action) => {
state.money = state.money - action.payload.money
return state;
})
.addCase(coffeeBeanOrdered, (state, action) => {
state.money = state.money + action.payload.money
return state;
})
.addCase(coffeeBeanRestocked, (state, action) => {
state.money = state.money - action.payload.money
return state;
})
}
})
module.exports = assetsSlice.reducer;
module.exports.cakeActions = assetsSlice.actions;
這裡我留有兩種寫法給大家做參考,這裡就看各位的喜好了,沒有對錯,如果硬要問我的話我可能會比較喜歡 builder 這種寫法,但真的是個人喜好啦!你各位可以各自選擇自己喜歡的做法就好,那第一種的話也明確地告訴你 redux-toolkit 是如何捨棄掉原先的 action type 又能同時控制其他的 initial state 的,原理上可能有所變動,但以結果上來說是一致的。
完成以上就可以來測試看看了,於終端機輸入以下指令:
node index.js
然後應該會看到以下訊息:
Initial State {
coffee: { numOfCoffee: 20 },
coffeeBean: { numOfCoffeeBean: 20 },
cake: { numOfCake: 20 },
assets: { money: 1000 }
}
更新 {
coffee: { numOfCoffee: 20 },
coffeeBean: { numOfCoffeeBean: 18 },
cake: { numOfCake: 20 },
assets: { money: 1010 }
}
更新 {
coffee: { numOfCoffee: 20 },
coffeeBean: { numOfCoffeeBean: 23 },
cake: { numOfCake: 20 },
assets: { money: 1005 }
}
那麼恭喜你又完成了一項商品,下一篇我們來完成最後一樣蛋糕的商品。