iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0
自我挑戰組

30天深入淺出Redux系列 第 5

Redux 深入淺出 - [ Day 5 ] 檔案拆分

  • 分享至 

  • xImage
  •  

接續上一篇我們成功地建立了一個 Redux 的完整程序於 index.js 之中,那這一篇就來分享常用的分層概念,首先我們先回到這張圖上。

https://ithelp.ithome.com.tw/upload/images/20220905/201290204LrBC0ZC4Y.png

讓我們按著這個圖表將 index.js 裡面的檔案做一下分類,然後分別另開三個資料夾為store, action, reducer,接著我們一樣先來處理 action 的部分,首先我們先把本來在定義 COFFEE_ORDERED 的部分用一個 js 檔案去做分離,並建立於action資料夾下,如以下:

// 我的範例上是簡單採types.js來命名,但當檔案多時通常還會再次拆分
const COFFEE_ORDERED = 'COFFEE_ORDERED';
// 這裡採node的方式做export/import
module.exports = {
  COFFEE_ORDERED,
};

這次我們嘗試分離 action 的部分,一樣建立在 action 資料夾下:

const { COFFEE_ORDERED } = require("./types")

// 建立Action
const orderCoffee = () => {
  return {
    type: COFFEE_ORDERED,
    payload: 1
  }
}
// 除上述function的方法以外也可以直接帶入object
const orderCoffeeObj = {
  type: COFFEE_ORDERED,
  payload: 1
}
// 但是我個人是不推薦這樣的做法,透過function還可以帶參數來設定,如下
const orderCoffeeByNum = (num) => {
  return {
    type: COFFEE_ORDERED,
    payload: num
  }
}

module.exports = {
  orderCoffee,
  orderCoffeeByNum,
  orderCoffeeObj
}

新建檔案後,再回到 index.js 裏面調整引入的部分:

const { orderCoffee, orderCoffeeObj, orderCoffeeByNum } = require('./action/order');

接著我們繼續來調整 reducer 的段落,在整理之前需要先講解一下,通常一個專案會有好多個 reducer 來實現多種不同的功能,所以在整併時通常會多一層來讓我們好分辨到底是哪個 reducer 和控制了哪些工能。

於是我們於 reducer 的資料夾下新建一個 orderReducer.js 的檔案,將我們之前寫好的段落移植過來:

// orderReducer.js
const { COFFEE_ORDERED } = require("../action/types");

const initialState = {
  numOfCoffee: 20,
  numOfCoffeeBean: 20,
  numOfCake: 20,
}
// 這部分和useReducer hook是一樣的
const orderReducer = (state = initialState, action) => {
  switch(action.type) {
    case COFFEE_ORDERED:
      return {
        ...state,
        numOfCoffee: state.numOfCoffee - action.payload
      }
    default: 
      return state;
  }
}

module.exports = { orderReducer }

完成後,我們在同路徑下新增一個 index.js 的檔案,並使用 redux 的 combineReducers function 來整合所有定義好的 reducer 檔案,如下:

// reducer/index.js
const { combineReducers } = require("redux");
const { orderReducer } = require('./orderReducer')

const reducers = combineReducers({
  orderReducer,
})

module.exports = {
  reducers
}

最後,我們來處理 store,這邊就比較單純一點了,我們一樣 CD 到 store 的資料夾下並新增 index.js 檔案,將原本在 ./index.js 的段落搬遷過來,如下:

// store/index.js
const { createStore } = require("redux");
const { reducers } = require("../reducer");

const store = createStore(reducers)

module.exports = {
  store,
}

做完以後將原本 ./index.js 重複的段落刪除後會得以下結果:

// 從剛才拆出來的地方引入
const { orderCoffee, orderCoffeeObj, orderCoffeeByNum } = require('./action/order');
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())
store.dispatch(orderCoffeeObj)
store.dispatch(orderCoffeeByNum(2))

unsubscribe()

這時候可以測試看看結果,應該會如以下:

initial state {
  orderReducer: { numOfCoffee: 20, numOfCoffeeBean: 20, numOfCake: 20 }
}
更新 {
  orderReducer: { numOfCoffee: 19, numOfCoffeeBean: 20, numOfCake: 20 }
}
更新 {
  orderReducer: { numOfCoffee: 18, numOfCoffeeBean: 20, numOfCake: 20 }
}
更新 {
  orderReducer: { numOfCoffee: 16, numOfCoffeeBean: 20, numOfCake: 20 }
}

這時候會發現 state 多了一個 key 為 orderReducer,承上所述,為了能夠整合許多不同 reducer 所以利用了combineReducers 的回傳結果就是如此。

那麼今天的內容就到這裡,下一篇我們來擴充一些複雜一點的功能吧!


上一篇
Redux 深入淺出 - [ Day 4 ] Reducer & Store
下一篇
Redux 深入淺出 - [ Day 6 ] 範例功能擴充
系列文
30天深入淺出Redux31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言