iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
自我挑戰組

30天深入淺出Redux系列 第 12

Redux 深入淺出 - [ Day 12 ] Redux Toolkit 簡介

  • 分享至 

  • xImage
  •  

什麼是 Redux toolkit ?

Redux Toolkit 官方的推薦使用的Redux工具,用於提高 Redux 開發。

https://ithelp.ithome.com.tw/upload/images/20220920/20129020A3LN6l7ECF.png

它包含幾個實用功能,可簡化最常見的 Redux 用例,包括存儲設置、定義 reducer、不可變更新邏輯,甚至無需手動編寫任何動作創建者或動作類型即可一次創建整個狀態Slice。 它還包括最廣泛使用的 Redux 插件,例如用於異步邏輯的 Redux Thunk 和用於編寫選擇器函數的 Reselect,以便您可以立即使用它們。

為何使用 Redux toolkit ?

說到這部分我們可以回想一下前面幾篇製作純 redux 環境時都遇到哪些繁瑣的工作?

  • 首先要定義 action type 於 types.js 檔案內。
    (當然可以不分離但實務上不分離就很蠢,相當於埋炸彈給自己人)
  • 然後是 action creator 就是我們一般於 action 做的 function 並定義回傳的 action object 應該長什麼樣子。
  • 接著於 reducer 內利用 switch case 來定義對應的 action type 和後續要對該 state 做的處理動作。
  • 相依性套件問題。
    (redux-thunk, redux-devtools-extension…. 或是其他套件可能要另外安裝)

這樣一整套繁瑣的流程,如果是大型專案的話有道理,但如果只是一般的 crud (ex: todo list) 這樣的小型專案,做起來就顯得很麻煩。

這就是選擇 redux toolkit 的好處了,一個 slice 裡面整合了 initialState, action, reducer,等一下使用時更能理解為何官方也推薦這類的做法。

Setup

為了方便大家理解簡化的過程,我們會另外起一個資料夾來做相同的處理,這裡的 demo 我會放在我 github 的 rtk folder 下面,那們練習的話可以自己找位置,也是會從 npm init 開始:

npm init -y

接著安裝 redux & redux-toolkit :

npm install redux @reduxjs/toolkit
or
yarn add redux @reduxjs/toolkit

因為 redux-toolkit 的 slice 會整合 action, reducer, types…., 所以我這次用 features 的資料夾來裝所有 redux 相關的檔案,然後我們一樣先從 store 做初始設定,首先在 feature 的資料夾內新增一個 store.js 的檔案:

// features/store.js
const { configureStore } = require('@reduxjs/toolkit');

const store = configureStore({
  reducer: {}
})

module.exports = {
  store,
}

使用 configureStore 來替換掉原本的 createStore,接著我麼先去搬遷原本的 action & reducer,將這些東西轉換成新的整合寫法 Slice.js,這邊我們新增一個叫 Slices 的資料夾,並試著搬遷其中的coffee看看,於 slices 資料夾下新增 coffeeSlice.js 並如下:

// features/slices/coffeeSlice.js
const createSlice = require('@reduxjs/toolkit').createSlice;

// 同 only 的 coffeeReducer initial state
const initialState = {
  numOfCoffee: 20
}

const coffeeSlice = createSlice({
  name: 'coffee',
  initialState,
  reducers: {
    // 這裡固定會有 sate & action 兩參數,直接對應於上面的 state
    coffeeOrdered: (state, action) => {
      state.numOfCoffee = state.numOfCoffee - action.payload
      return state;
    },
    coffeeRestocked: (state, action) => {
      state.numOfCoffee = state.numOfCoffee + action.payload
      return state;
    },
  }
})
// 這邊就要注意 default 的情況下輸出 reducer 對應的 action function 會從 coffeeActions 引入
module.exports = coffeeSlice.reducer;
module.exports.coffeeActions = coffeeSlice.actions;

在 createSlice 內 actions 對應的就會是你 reducers 裡面定義的 function name,最後的 export 也很重要,作為 store 的整合器,你需要做的是輸出 slice.reducer,也就是說於前一步 store.js 需要引入的是 default 值,而在 dispatch 要使用的則為 coffeeActions。

那麼,有了 reducer 之後我們回過頭來整併進 store:

// store.js
const configureStore = require('@reduxjs/toolkit').configureStore;
const coffeeReducer = require('./slices/coffeeSlice');

const store = configureStore({
  reducer: {
    coffee: coffeeReducer,
  }
})

module.exports = { store }

至此我們已經完成 action → action creator → reducer,對你沒看錯,一個完整的 redux data flow 已經完成,不相信嗎?我們一樣做一個 index.js 來測試看看指令,於根目錄下新增 index.js,如下:

// ./index.js
const { store } = require('./features/store');
const coffeeActions = require('./features/slices/coffeeSlice').coffeeActions;

console.log('Initial State', store.getState());
const unsubscribe = store.subscribe(() => console.log('更新', store.getState()));

store.dispatch(coffeeActions.coffeeOrdered(1));
store.dispatch(coffeeActions.coffeeOrdered(4));
store.dispatch(coffeeActions.coffeeRestocked(10));
unsubscribe();

然後於終端機 node index.js,應該會有以下訊息:

Initial State { coffee: { numOfCoffee: 20 } }
更新 { coffee: { numOfCoffee: 19 } }
更新 { coffee: { numOfCoffee: 15 } }
更新 { coffee: { numOfCoffee: 25 } }

恭喜,你已經完成原本於 redux 需要做的兩個檔案的量了,下一篇我們陸續將其他的 reducer 也用相同的方式正並進來。


上一篇
Redux 深入淺出 - [ Day 11 ] Redux-thunk 非同步 Action
下一篇
Redux 深入淺出 - [ Day 13 ] Redux Toolkit Slice
系列文
30天深入淺出Redux31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言