redux原始碼分析之五:applyMiddleware

Happi發表於2018-09-06

歡迎關注redux原始碼分析系列文章:
redux原始碼分析之一:createStore.js
redux原始碼分析之二:combineReducers.js
redux原始碼分析之三:bindActionCreators.js
redux原始碼分析之四:compose.js
redux原始碼分析之五:applyMiddleware

redux中介軟體其實非常簡單,中介軟體的目的只有一個:在dispatch前後,執行一些程式碼,達到增強dispatch的效果,有點類似裝飾器的原理。

applyMiddleware需要結合createStore函式來看,appleyMiddleware就是createStore的第三個引數enhancer,比如,對redux-logger中介軟體,其使用方式如下:

import { applyMiddleware, createStore } from `redux`;
import { createLogger } from `redux-logger`;

const logger = createLogger();
const store = createStore(
  reducer,
  applyMiddleware(logger)
)

applyMiddleware檔案的原始碼如下:

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

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

    return {
      ...store,
      dispatch
    }
  }
}

一、applyMiddleware函式的引數

  1. 接受多個引數,每一個引數,都是一箇中介軟體

二、函式的返回值

函式的返回值本身,也是另外一個函式,而這個函式,接受的引數是createStore,結合createStore的前幾行原始碼來看:

export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === `function` && typeof enhancer === `undefined`) {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== `undefined`) {
    if (typeof enhancer !== `function`) {
      throw new Error(`Expected the enhancer to be a function.`)
    }

    return enhancer(createStore)(reducer, preloadedState)
  }
  //其餘程式碼這裡忽略
}

可以看到,createStore的第三個引數ehancer如果是一個函式的話,就會優先執行ehancer,然後再再enhancer內部呼叫createStore函式,所以,createStore其實只會執行一些,也只會生成一個store。

三、關鍵程式碼解釋

我新增了程式碼註釋如下:(關於compose函式的解釋,請參考文章:redux原始碼分析之四:compose.js):

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    //這裡會原封不動的執行createStore,並根據入參生成一個store
    const store = createStore(reducer, preloadedState, enhancer)
    //把dispatch從store中取出來
    let dispatch = store.dispatch
    let chain = []
    
    //這裡約定了所有的redux中介軟體只能使用的api就是2個,getState和dispatch
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    對每一箇中介軟體,執行中介軟體函式,並將中介軟體api物件傳入函式,用chain變數接收中介軟體執行結果的其返回值
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    //這裡用到了compose函式,分別按順序從後往前執行每一箇中介軟體,並且前一箇中介軟體的返回值作為後一箇中介軟體的入參,所有中介軟體的第一個入參是原始的store.dispatch
    dispatch = compose(...chain)(store.dispatch)

    //最後返回store物件,只是,使用了經過中介軟體加工過的dispatch物件,替換掉原始的dispatch物件
    return {
      ...store,
      dispatch
    }
  }
}

四、總結

redux中介軟體只有一個目的:在dispatch前後,執行一些程式碼,達到增強dispatch的效果,有點類似裝飾器的原理。,理解好了這一點就ok了。
下一篇文章會給大家帶來一個最簡單的redux中介軟體,敬請期待。

相關文章