理解Redux中間件

中間件是什麼

如果你用過express.js之類的web框架,對中間件(Middleware)這個概念可能不會陌生。中間件其實就是一種獨立運行於各個框架組件之間的膠水代碼。在Express.js或Koa等框架中,中間件通常是運行在收到請求到處理請求之間,可是實現日誌記錄、身份認證等預處理操作。而在Redux裏,中間件是運行在action發送出去,到達reducer之間的一段代碼。

編寫中間件

日誌記錄是開發過程中常用的一個功能,你可以選擇侵入業務邏輯來記錄日誌(不推薦),也可以選擇使用中間件來實現這個功能。接下來讓我們編寫一個常用的日誌記錄中間件:

const loggerMiddleware = store => next => action => {
  console.group(action.type);
  console.log('action: ', action);
  const result = next(action);
  console.log('next state: ', store.getState());
  console.groupEnd(action.type);
  return result;
}

使用中間件的時候,要在初始化store的時候利用applyMiddleware注入進去:

const store = createStore(
    rootReducer,
    applyMiddleware(loggerMiddleware)
)

這樣,我們在每次觸發action的時候就能記錄我們所需要的信息。同樣的方式,也可以實現日誌上報等功能。

組合中間件

中間件其實是一種高層次的抽象,可以將核心領域業務和基礎架構邏輯解耦開來。而多箇中間件可以組合使用,從而使每一箇中間件能夠保持“小而美”的特性。

const store = createStore(
    rootReducer,
    applyMiddleware(thunk, loggerMiddleware)
)

其中applyMiddleware函數可以接收多箇中間件,源碼如下:

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    var store = createStore(reducer, preloadedState, enhancer)
    var dispatch = store.dispatch
    var chain = []

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  const last = funcs[funcs.length - 1]
  const rest = funcs.slice(0, -1)
  return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}

我們可以看到它主要做了幾個工作:

  1. 返回一個高階函數,這個函數中會初始化store和重寫dispatch邏輯,以便後續使用。
  2. store.getState,dispatch傳入每個中間件中,並收集調用鏈結果。

之後在應用中所有使用的dispatch都將是修改過的邏輯,從中我們可以看出有點面向切面編程的味道,可以好好體會一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章