天天看點

細說 Redux Toolkit 1 : 重新回顧 Redux細說 Redux Toolkit 1 : 重新回顧 Redux前言Redux 資料流 & 核心概念實作核心示例Redux Toolkit 概述參考連接配接

細說 Redux Toolkit 1 : 重新回顧 Redux

文章目錄

  • 細說 Redux Toolkit 1 : 重新回顧 Redux
  • 前言
  • Redux 資料流 & 核心概念
  • 實作核心示例
    • State、Reducer
    • Store
    • Action、ActionCreator
    • Middleware、Thunk
  • Redux Toolkit 概述
  • 參考連接配接

前言

接下來幾篇我們要來說說關于 redux 官方提供的新工具 Redux Toolkit。開篇第一篇我們先來重新梳理一下 Redux 的基本概念。

Redux 資料流 & 核心概念

本篇預設讀者已經對于 Redux 有一些基本的認識,如果是零基礎也建議讀者先去看看 Redux 官方的介紹

  • Redux Essentials, Part 1: Redux Overview and Concepts

接下來我們從 Redux 官方給出的資料流圖來重新梳理 Redux 狀态管理的流程

細說 Redux Toolkit 1 : 重新回顧 Redux細說 Redux Toolkit 1 : 重新回顧 Redux前言Redux 資料流 & 核心概念實作核心示例Redux Toolkit 概述參考連接配接
  • 全局狀态

整個 Redux 的全局資料都存儲在 state 對象裡面,然後通常我們會透過

Provider

的方式基于 Context API 注入到 React 元件當中;當然我們也可以直接使用 store API 的

getState

subscribe

dispatch

自行訂閱并管理狀态的變化。

  • 處理變更

在 view 層基于狀态進行展示之後,不論是透過使用者操作還是其他外部事件,我們在控制層需要透過所謂的 dispatch 方法送出一個 Action 對象,其中 Action 通常使用

{ type, payload }

的資料結構包含操作的類型與參數。我們也可以透過利用中間件來識别更多不同資料結構的 Action 對象(例如 redux-thunk 接受的 Action 實際上是一個 function)

  • 中間件

Redux 所提出的中間件模式大大地提高了 Redux 架構的靈活性,我們可以利用中間件進行如過濾、監控、打點、校驗,甚至是對于 Action 結構的擴充。經過中間件鍊的處理才将最終傳回的 Action 對象送出到 store 中的 Reducer 重新計算下一次的 state 狀态。

到此 Redux 的單向資料流結構就完成閉環,下面我們分别看到每個核心概念的簡單實作示例。

實作核心示例

State、Reducer

Redux 當中的全局狀态實際上是 Redux 自身在管理的,我們需要做的隻是定義好 State 的資料結構,然後透過實作 Reducer 來明确每一次更新時該如何計算下一個 State 狀态。

interface CounterState {
  value: number;
}

const initialState: CounterState = {
  value: 0,
};

function counterReducer(state: CounterState = initialState, action): CounterState {
  // counting next state base on action
  return newState;
}
           

在每次使用 dispatch 送出變更的時候都會觸發 reducer 的調用,并計算出下一個 state 的快照。

Store

建立好 reducer 之後就可以建立完整的狀态管理中心 store

如果我們有多個 reducer 的時候可以使用 combineReducers 進行合并

const rootReducer = combineReducers({
  counter: counterReducer,
  meta: metaReducer,
})
const store = createStore(rootReducer);
           

注意當我們使用多個 reducer 的時候,每個 reducer 傳回的狀态就會分别對應 state 下不同字段,例如

state.counter.value

state.meta.xxx

等。

  • 消費 store

第一種 store 的使用方式就是直接掉用 store 的 API

store.getState()
store.subscribe(cb)
store.dispatch(action)
           

第二種就是我們在 React 裡面最常用的基于 Context API 的 react-redux 庫

function App() {
  return (
    <Provider store={store}>
      <Body/>
    </Provider>
  )
}
           

元件内部可以使用 react-redux 提供的

connect

HOC 元件将狀态映射到 props 之中;或是使用

<Consumer>

配合 render children 的方式實作

function Body() {/*...*/}
export default connect(mapStateToProps, mapDispatchToProps)(Body)
           
function App() {
  return (
    <Provider store={store}>
      <Consumer>
        {(props) => <Body/>}
      </Consumer>
    </Provider>
  )
}
           

Action、ActionCreator

前面在資料流的部分我們提過,要修改 Redux 的狀态隻能透過 dispatch 送出變更,并在 action 内附帶相關資訊。

store.dispatch({ type: 'counter/increment' });
store.dispatch({ type: 'counter/setNumber', payload: 10 });
           

标準情況下我們會傳遞一個帶 type 字段的簡單對象來表達操作類型。其他情況我們也可以配合中間件的擴充來定義新的變更資訊資料結構。下面的例子是使用 redux-thunk 中間件來實作異步狀态修改的示例

store.dispatch((dispatch, getState) => {
  queryAPI().then((res) => {
    dispatch({ type: 'counter/init', payload: res.data.count });
  })
});
           

下面我們在詳細說明中間件是如何運作的。

  • Action Creator

我們可以看到每次送出變更總要寫出完整的 action 對象非常麻煩,是以在大多數的實踐中我們會定義一個 actionCreator,将 action 的生成轉換成函數的掉用如下

const incrementAction = () => ({ type: 'counter/increment' });

store.dispatch(incrementAction())
           

Middleware、Thunk

在基礎版本的資料流中,dispatch 的 action 對象會直接傳遞給 reducer 進行解析并計算下一個 state。然而在傳遞給 reducer 之前我們可以透過添加中間件來進行額外的操作。基礎的中間件函數标簽如下

const middlerware = store => next => action => {
  // logic
  next();
}
           

中間件會像連結清單一樣将多個中間件處理過程串聯起來,然後使用

next

方法來将 action 傳遞給下一個中間件。最經典的例子就是日志中間件

const loggerMiddleware = store => next => action => {
  logger.log('dispatch start', action);
  const res = next(action);
  logger.log('dispatch end', store.getState());
  return res;
};
           

我們需要注意的是 next 傳回的是上一個中間件的傳回産物,通常但不一定就是 reducer 的 state 對象,是以我們如果不做任何處理于修改的話直接傳回上一個中間件的結果保證資料正确透傳即可。

Redux Toolkit 概述

我們回顧完 Redux 的資料流與所有核心概念的代碼使用案例,不難發現 Redux 的實踐過程其實是相當冗長的。

建構一個基于 Redux 的全局狀态管理,我們需要經曆以下步驟:

  1. 定義全局狀态資料結構
  2. 定義 Reducer 如何計算下一次 state 的邏輯
    1. 多 Reducer 需要使用 CombineReducers
  3. 使用 applyMiddleware 或是其他 enhancers 建構中間件連結清單
  4. 最後基于 reducers 和所有 enhancers 建立 store 對象
  5. 在 React 元件中使用 Provider 與 connect HOC 将全局狀态注入。

每次我們想要新增新的 action 操作類型的時候:

  1. 定義新的 action type,并明确 payload 資料結構
  2. 往 Reducer 中添加新的 type 判斷分支,以及新的狀态計算邏輯
  3. 建立新的 actionCreator 加速 dispatch 掉用過程

以上步驟反複執行的時候不免感到異常乏味而且重複,同時 type、actionCreator、reducers 之間又會存在隐式的字面量關聯,很多時候需要開發者非常小心,否則就會産生變更送出無效的情形。

Redux Toolkit 的出現就是提供一些對于 Redux API 的封裝和文法糖,幫助使用者從重複勞動中解放,能夠更好的專注在業務邏輯以及狀态轉換邏輯本身。

接下來幾篇我們會将幾個 Redux Toolkit 提供的經典 API 與舊有的 Redux 用法作比較,不管是從舊版本 Redux 遷移過來的使用者,或是全新的 Redux 使用者來說,能夠更加細緻的了解每一個封裝背後的構想。

參考連接配接

Title Link
Redux Essentials, Part 1: Redux Overview and Concepts https://redux.js.org/tutorials/essentials/part-1-overview-concepts
Redux Toolkit https://redux-toolkit.js.org/