redux源碼圖解:createStore 和 applyMiddleware

在研究 redux-saga時(shí),發(fā)現(xiàn)自己對(duì) redux middleware 不是太了解,因此,便決定先深入解讀一下 redux 源碼。跟大多數(shù)人一樣,發(fā)現(xiàn) redux源碼 真的很精簡(jiǎn),目錄結(jié)構(gòu)如下:

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

index.js 中導(dǎo)出了5個(gè)模塊,即外部可用的:

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

然而,當(dāng)真正解讀的時(shí)候,發(fā)現(xiàn)還真是有點(diǎn)吃不消,經(jīng)過(guò)幾天的硬啃之后,只能說(shuō):終于等到你,還好我沒(méi)放棄。。。(自帶BGM)

這里,我可能不會(huì)仔細(xì)去分析它的源碼,但會(huì)就自己的理解進(jìn)行梳理概括,具體的對(duì)我很有幫助的文章會(huì)放到結(jié)尾參考處。

首先是對(duì) createStore 、 applyMiddlewarecompose 的梳理,因?yàn)檫@3個(gè)模塊存在相互調(diào)用的關(guān)系,其關(guān)系圖如下(高清圖請(qǐng)查看 redux源碼圖解之createStore和applyMiddleware):

redux源碼圖解之createStore和applyMiddleware

1. 每個(gè)模塊的作用

createStore 的函數(shù)的作用就是生成一個(gè) store 對(duì)象,這個(gè)對(duì)象具有5個(gè)方法:

return {
    dispatch,  // 傳入 action,調(diào)用 reducer 及觸發(fā) subscribe 綁定的監(jiān)聽函數(shù)
    subscribe,
    getState,
    replaceReducer,  // 用新的 reducer 代替當(dāng)前的 reducer,使用不多
    [$$observable]: observable
  }

applyMiddleware 函數(shù)的作用就是對(duì) store.dispatch 方法進(jìn)行增強(qiáng)和改造,使得在發(fā)出 Action 和執(zhí)行 Reducer 之間添加其他功能。

compose 函數(shù)則是 applyMiddleware 函數(shù)的核心,其會(huì)形成串聯(lián)的函數(shù)調(diào)用關(guān)系,用于增強(qiáng) dispatch 方法。

2. 模塊之間的調(diào)用關(guān)系

(i) 首先,createStore 模塊會(huì)對(duì)傳入的參數(shù)進(jìn)行判斷,分別處理不同參數(shù)的情況,當(dāng)傳入 applyMiddleware(...middleware) 的時(shí)候,就會(huì)返回 applyMiddleware(...middleware) 執(zhí)行之后的高階函數(shù),即:

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

(ii)然后,就進(jìn)入了 applyMiddleware 模塊內(nèi)部的邏輯,從 createStore 返回的高階函數(shù),其傳入的參數(shù)是沒(méi)有 enhancer 的,因此走的是 createStore 函數(shù)中沒(méi)有傳入 enhancer 的邏輯,用于先獲得沒(méi)有中間件時(shí)返回的 store。

// 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的中間件數(shù)組

    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 對(duì)象。將該對(duì)象傳入中間件 middleware 中,形成中間件數(shù)組 chain

其中,middleware 的范式是:(store) => (next) => (action) => {},將 middlewareAPI 傳入middleware 后,中間件便獲得了 {getState, dispacth}。至此,chain 中間件數(shù)組中包含的每個(gè)中間件的形式都變成了 (next) => (action) => {} 的形式。

(iiii)最后,調(diào)用 compose 函數(shù),如 chian = [middleware1, middleware2, middleware3],則 dispatch = compose(...chain)(store.dispatch),即執(zhí)行 middleware1(middleware2(middleware3(store.dispatch))),然后賦值給 dispatch。

總之,不管是否有 applyMiddleware,createStore 的結(jié)果都是輸出一個(gè) store 對(duì)象,而 applyMiddleware 則可以對(duì) store 對(duì)象中的 dispatch 進(jìn)行改造。

3. 參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 本文 有配套視頻,可以酌情觀看。 文中內(nèi)容因各人理解不同,可能會(huì)有所偏差,歡迎朋友們聯(lián)系我討論。 文中所有內(nèi)...
    珍此良辰閱讀 12,168評(píng)論 23 111
  • http://gaearon.github.io/redux/index.html ,文檔在 http://rac...
    jacobbubu閱讀 80,409評(píng)論 35 198
  • 為什么dispatch需要middleware 上圖表達(dá)的是 redux 中一個(gè)簡(jiǎn)單的同步數(shù)據(jù)流動(dòng)的場(chǎng)景,點(diǎn)擊 b...
    一個(gè)胖子的我閱讀 2,122評(píng)論 1 9
  • “中間件”這個(gè)詞聽起來(lái)很恐怖,但它實(shí)際一點(diǎn)都不難。想更好的了解中間件的方法就是看一下那些已經(jīng)實(shí)現(xiàn)了的中間件是怎么工...
    Jmingzi_閱讀 1,769評(píng)論 1 7
  • 在學(xué)習(xí)了redux過(guò)程中,了解到中間件這個(gè)名詞,但是我看了十遍,也完全就是懵逼的狀態(tài)。于是又重復(fù)敲了幾次代碼也不能...
    綽號(hào)陸拾柒閱讀 597評(píng)論 0 0

友情鏈接更多精彩內(nèi)容