redux源碼圖解:createStore 和 applyMiddleware

在研究 redux-saga時,發現本身對 redux middleware 不是太瞭解,所以,便決定先深刻解讀一下 redux 源碼。跟大多數人同樣,發現 redux源碼 真的很精簡,目錄結構以下:javascript

|—— utils
    |—— warnings.js
|—— applyMiddleware.js
|—— bindActionCreator.js
|—— combineReducers.js
|—— compose.js
|—— createStore.js
|—— index.js

index.js 中導出了5個模塊,即外部可用的:html

export {
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose
}

然而,當真正解讀的時候,發現還真是有點吃不消,通過幾天的硬啃以後,只能說:終於等到你,還好我沒放棄。。。(自帶BGM)java

這裏,我可能不會仔細去分析它的源碼,但會就本身的理解進行梳理歸納,具體的對我頗有幫助的文章會放到結尾參考處。react

首先是對 createStoreapplyMiddlewarecompose 的梳理,由於這3個模塊存在相互調用的關係,其關係圖以下(高清圖請查看 redux源碼圖解之createStore和applyMiddleware):git

redux源碼圖解之createStore和applyMiddleware

1. 每一個模塊的做用

createStore 的函數的做用就是生成一個 store 對象,這個對象具備5個方法:github

return {
    dispatch,  // 傳入 action,調用 reducer 及觸發 subscribe 綁定的監聽函數
    subscribe,
    getState,
    replaceReducer,  // 用新的 reducer 代替當前的 reducer,使用很少
    [$$observable]: observable
  }

applyMiddleware 函數的做用就是對 store.dispatch 方法進行加強和改造,使得在發出 Action 和執行 Reducer 之間添加其餘功能。redux

compose 函數則是 applyMiddleware 函數的核心,其會造成串聯的函數調用關係,用於加強 dispatch 方法。數組

2. 模塊之間的調用關係

(i) 首先,createStore 模塊會對傳入的參數進行判斷,分別處理不一樣參數的狀況,當傳入 applyMiddleware(...middleware) 的時候,就會返回 applyMiddleware(...middleware) 執行以後的高階函數,即:架構

// createStore.js
if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    // 這裏的 enhancer 是 applyMiddleware(...) 執行後的高階函數,傳參無 enhancer
    return enhancer(createStore)(reducer, preloadedState)
  }

(ii)而後,就進入了 applyMiddleware 模塊內部的邏輯,從 createStore 返回的高階函數,其傳入的參數是沒有 enhancer 的,所以走的是 createStore 函數中沒有傳入 enhancer 的邏輯,用於先得到沒有中間件時返回的 store。app

// applyMiddleware.js
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []  // 用於存放獲取了store的中間件數組

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

    return {
      ...store,
      dispatch
    }
  }
}

(iii)接着,獲取最原始的 store 的 getStatedispatch,封裝於 middlewareAPI 對象。將該對象傳入中間件 middleware 中,造成中間件數組 chain

其中,middleware 的範式是:(store) => (next) => (action) => {},將 middlewareAPI 傳入middleware 後,中間件便得到了 {getState, dispacth}。至此,chain 中間件數組中包含的每一箇中間件的形式都變成了 (next) => (action) => {} 的形式。

(iiii)最後,調用 compose 函數,如 chian = [middleware1, middleware2, middleware3],則 dispatch = compose(...chain)(store.dispatch),即執行 middleware1(middleware2(middleware3(store.dispatch))),而後賦值給 dispatch

總之,無論是否有 applyMiddlewarecreateStore 的結果都是輸出一個 store 對象,而 applyMiddleware 則能夠對 store 對象中的 dispatch 進行改造。

3. 參考

相關文章
相關標籤/搜索