Redux中間件原理解析

redux項目開發(fā)過程中扛伍,有時候我們需要自己去編寫一些redux中間件稚伍, 但是中間件用法法一般都像下面這樣子:

export function myMidware ({dispatch, getState}) {
    //  返回一個接收dispatch為參數(shù)的函數(shù)
    return (dispatch) => (action) => {
        // do something
        return dispatch(action)
    }
}

//使用中間件
const store = createStore(reducer, applyMiddleware(myMidware))

一看到這種套娃的寫法间校,整個人都是懵的枯途。那么接下來我就帶著問題給大家理解理解, 為什么中間件函數(shù)非要這么寫, applyMiddleware究竟做了什么

廢話不多說首先來看看applyMiddleware的源碼杀狡,看看它到底做了啥:

// 首先這個函數(shù)接收多個中間件函數(shù)颜骤,放在middlewares的數(shù)組中
export default function applyMiddleware(...middlewares) {
  // 返回一個接受createStore參數(shù)的函數(shù), 這個函數(shù)執(zhí)行之后應(yīng)該返回一個增強版createStore函數(shù)
  // (...args) => { ... } 這里可以看成是一個增強版的createStore函數(shù)(從createStore源碼可以看出)
  return createStore => (...args) => {
    const store = createStore(...args)
    // 這里的dispatch是不希望你在創(chuàng)建中間件的時候調(diào)用它
    let dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }

    // 把原版store的api構(gòu)造成對象準(zhǔn)備傳遞給中間件
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args) // 個人感覺這里不給用 其實就沒必要給到中間件構(gòu)造函數(shù)里面去
    }
    // 把構(gòu)造好的api對象傳遞給中間件捣卤,讓中間件擁有可以訪問store的能力
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // compose函數(shù)可以把多個中間件函數(shù)的數(shù)組,合成一個中間件函數(shù)的形式八孝,然后再執(zhí)行中間件
    // 并將得到的新的函數(shù) 當(dāng)作新的dispatch函數(shù)
    dispatch = compose(...chain)(store.dispatch)
    // 返回一個增強了dispatch函數(shù)的store
    return {
      ...store,
      dispatch
    }
  }
}

從上面的代碼解讀可以看出董朝, applyMiddleware函數(shù),做了已下事情:

  • 返回一個新的createStore函數(shù)干跛,這里叫它 superCreateStore函數(shù)
  • supterCreateStore函數(shù)中子姜,執(zhí)行了createStore函數(shù),可見 args其實就是reducer楼入,看createStore函數(shù)源碼可知傳入的就是reducer
  • superCreateStore函數(shù)中執(zhí)行中間件函數(shù)哥捕,得到了一個新的dispatch函數(shù),這里叫它superDispatch
  • 最后supterCreateStore函數(shù)返回了一個新的store對象嘉熊,這個對象改造了dispatch函數(shù)

看完了源碼遥赚,接下來就開始理解這個思路了,套娃開始:

首先是applyMiddleware

  • createStore( reducer, enhancer) 返回一個 store
  • applyMiddleware(...middleWares) 返回 enhancer增強器
  • enhencer就是一個函數(shù)阐肤,接收 createStore為參數(shù)凫佛,返回一個superCreateStore函數(shù)
  • superCreateStore函數(shù)和createStore一樣讲坎,接手reducers作為參數(shù),返回一個新的store

再來理解中間件函數(shù)執(zhí)行過程

  • superCreateStore 中愧薛,第一次執(zhí)行中間傳入了 middlewareAPI, 得到了dispatch增強器
  • dispatch增強器通過compose組合后晨炕,還是個dispatch增強器,再執(zhí)行傳入store.dispatch毫炉,也就是store原本的dispatch函數(shù)作為參數(shù) 得到了superDispatch函數(shù)

到此我們就已經(jīng)完全理解了中間件的執(zhí)行過程及其作用瓮栗,其實就是返回了一個dispatch增強器函數(shù)的函數(shù),得到的增強器函數(shù)接收dispatch返回一個新的dispatch 函數(shù)瞄勾,dispatch執(zhí)行后會返回action费奸,就是這樣的邏輯, 這樣我們就可以在actiondispatchstore之前丰榴,做一些處理货邓。


compose函數(shù)正是一個鏈?zhǔn)秸{(diào)用dispatch增強器的函數(shù),每次執(zhí)行一個函數(shù)都會返回一個增強過的dispatch函數(shù)四濒,給下一個中間件换况, 下面貼一下compose函數(shù)的代碼, 感興趣的可以理解一下:

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

  if (funcs.length === 1) {
    return funcs[0]
  }
  // 這里的args就是dispatch
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

傳送門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載盗蟆,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者戈二。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市喳资,隨后出現(xiàn)的幾起案子觉吭,更是在濱河造成了極大的恐慌,老刑警劉巖仆邓,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲜滩,死亡現(xiàn)場離奇詭異,居然都是意外死亡节值,警方通過查閱死者的電腦和手機徙硅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搞疗,“玉大人嗓蘑,你說我怎么就攤上這事∧淠耍” “怎么了桩皿?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長幢炸。 經(jīng)常有香客問我泄隔,道長,這世上最難降的妖魔是什么宛徊? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任梅尤,我火速辦了婚禮柜思,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巷燥。我一直安慰自己赡盘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布缰揪。 她就那樣靜靜地躺著陨享,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钝腺。 梳的紋絲不亂的頭發(fā)上抛姑,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天,我揣著相機與錄音艳狐,去河邊找鬼定硝。 笑死,一個胖子當(dāng)著我的面吹牛毫目,可吹牛的內(nèi)容都是我干的蔬啡。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼镀虐,長吁一口氣:“原來是場噩夢啊……” “哼箱蟆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刮便,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤空猜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后恨旱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辈毯,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年搜贤,在試婚紗的時候發(fā)現(xiàn)自己被綠了漓摩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡入客,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出腿椎,到底是詐尸還是另有隱情桌硫,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布啃炸,位于F島的核電站铆隘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏南用。R本人自食惡果不足惜膀钠,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一掏湾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肿嘲,春花似錦融击、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至封救,卻和暖如春拇涤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背誉结。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工鹅士, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惩坑。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓掉盅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旭贬。 傳聞我的和親對象是個殘疾皇子怔接,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內(nèi)容