如前一篇我們已經知道如何拆分檔案,並也了解到 redux 一個完整的資料更新流程會歷經哪些步驟,那麼我們回過頭來想一下,一個咖啡廳還會有哪些動作需要擴充。
首先,我們先加上營利的概念在原本的 state 當中好了,然後大概如下分兩個層面來新增。
那麼,我們再回到 orderReducer 的檔案裡修改 initialState 的結構,加上營收的 key:
// ...省略
const initialState = {
numOfCoffee: 20,
numOfCoffeeBean: 20,
numOfCake: 20,
assets: 1000,
}
// ...省略
接著我們試著同樣的邏輯修改一個補貨的 action 吧!
我們先移動到 action 的資料夾內,還記得我們將 type 拆分出來了嗎?那麼我們就先修改 types.js 的檔案,如下:
const COFFEE_ORDERED = 'COFFEE_ORDERED';
const COFFEE_RESTOCKED = 'COFFEE_RESTOCKED';
module.exports = {
COFFEE_ORDERED,
COFFEE_RESTOCKED
};
修改完成後,我們另外新增一個檔案做屬於補貨部分的 action 檔案,那麼這個部分就要看個人考量了,通常會以一個 reducer 會對應一個 action 的檔案,但這裡的話想說讓大家多練習熟悉這樣的寫法所以另外拆分出來,實務上應用合併是完全沒問題的。
這裡的話我簡單 naming 一個 restock.js 的檔案,如下:
// restock.js
const { COFFEE_RESTOCKED } = require("./types")
// 數量要相加,錢花掉了要相減
const restockCoffee = (qty, pay) => {
return {
type: COFFEE_RESTOCKED,
payload: {
qty: qty,
pay: pay,
}
}
}
module.exports = {
restockCoffee
}
這邊的寫法就因人而異,沒有固定說一定要照我的才是正確,也可以直接要求傳入一個物件給 payload 去接。
接著我們回過頭來調整一下買咖啡的金額,如下:
// order.js
const { COFFEE_ORDERED } = require("./types")
const orderCoffee = (qty, income) => {
return {
type: COFFEE_ORDERED,
payload: {
qty: qty,
income: income
}
}
}
module.exports = {
orderCoffee,
}
這邊為了保留使用這個 function 的彈性,我還是以帶入參數的方式做調整,當然你們可以照自己的喜好做調整。
接著,我們回到 orderReducer 的檔案來做對應的 function 要處理的邏輯,如下:
// orderReducer.js
const { COFFEE_ORDERED, COFFEE_RESTOCKED } = require("../action/types");
const initialState = {
numOfCoffee: 20,
numOfCoffeeBean: 20,
numOfCake: 20,
assets: 1000,
}
// 這部分和useReducer hook是一樣的
const orderReducer = (state = initialState, action) => {
switch(action.type) {
case COFFEE_ORDERED:
// 顧客買 => 商品-, 營收+
return {
...state,
numOfCoffee: state.numOfCoffee - action.payload.qty,
assets: state.assets + action.payload.income
}
case COFFEE_RESTOCKED:
// 補貨 => 商品+, 營收-
return {
...state,
numOfCoffee: state.numOfCoffee + action.payload.qty,
assets: state.assets - action.payload.pay
}
default:
return state;
}
}
module.exports = { orderReducer }
最後我們回到 index.js 來測試看看吧!
// ./index.js
const { orderCoffee } = require('./action/order');
const { restockCoffee } = require('./action/restock');
const { store } = require('./store');
// 來試試拿取 initialState
console.log('initial state', store.getState());
// 當state change時可以觸發的 callback
const unsubscribe = store.subscribe(() => console.log('更新', store.getState()))
// 讓我們來試看看點餐
store.dispatch(orderCoffee(2, 20))
// 測試補咖啡
store.dispatch(restockCoffee(20, 10))
unsubscribe()
應該會得到以下結果:
initial state {
orderReducer: { numOfCoffee: 20, numOfCoffeeBean: 20, numOfCake: 20, assets: 1000 }
}
更新 {
orderReducer: { numOfCoffee: 18, numOfCoffeeBean: 20, numOfCake: 20, assets: 1020 }
}
更新 {
orderReducer: { numOfCoffee: 38, numOfCoffeeBean: 20, numOfCake: 20, assets: 1010 }
}
到此,我們已經完成簡單咖啡部分的功能,下一篇我們來擴充咖啡豆部分的功能!