iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
自我挑戰組

30天深入淺出Redux系列 第 6

Redux 深入淺出 - [ Day 6 ] 範例功能擴充

  • 分享至 

  • xImage
  •  

如前一篇我們已經知道如何拆分檔案,並也了解到 redux 一個完整的資料更新流程會歷經哪些步驟,那麼我們回過頭來想一下,一個咖啡廳還會有哪些動作需要擴充。

首先,我們先加上營利的概念在原本的 state 當中好了,然後大概如下分兩個層面來新增。

https://ithelp.ithome.com.tw/upload/images/20220906/20129020O2STsIl8LO.png

那麼,我們再回到 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 }
}

到此,我們已經完成簡單咖啡部分的功能,下一篇我們來擴充咖啡豆部分的功能!


上一篇
Redux 深入淺出 - [ Day 5 ] 檔案拆分
下一篇
Redux 深入淺出 - [ Day 7 ] 範例商品 - 咖啡豆
系列文
30天深入淺出Redux31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言