redux源碼分析

這篇文章會(huì)很長(zhǎng)衫画。redux源碼讀起來(lái)并不困難睡榆。讀懂redux的源碼有利于更好的使用redux。
但是react-redux復(fù)雜多缠导。所以分階段寫廉羔。

redux源碼分析

在使用redux中,比較重要的三個(gè)函數(shù): createStore,store.dispatch,reducer酬核。其中有一個(gè)比較難以理解的點(diǎn)是,為什么reducer每次都要返回一個(gè)新的變量蜜另。我們先來(lái)分析 createStore函數(shù)。
redux整個(gè)設(shè)計(jì)遵循的是訂閱-更新模式嫡意。

export default function createStore(reducer, preloadedState, enhancer) {
  let currentReducer = reducer
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false


  function getState() {
    if (isDispatching) {
      throw new Error(
        'You may not call store.getState() while the reducer is executing. ' +
          'The reducer has already received the state as an argument. ' +
          'Pass it down from the top reducer instead of reading it from the store.'
      )
    }

    return currentState
  }
}

其中举瑰,currentState是維持在createStore的中的變量。也是存儲(chǔ)整個(gè)工程的state數(shù)據(jù)的變量蔬螟。

  • dispatch函數(shù)
  function dispatch(action) {
   ...

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

dispatch函數(shù)可以看到reducer的設(shè)計(jì)思想此迅。currentReducer是我們調(diào)用createStore時(shí)傳遞進(jìn)來(lái)的reducer函數(shù)。一般reducer函數(shù)是這樣定義的:

const reducers = (state = initialState, action) => {
    let newState = Object.assign({}, state);
    switch (action.type) {
        case types.GET_ORDERS:
            newState.orderInfo = action.response;

        case types.GET_GOODS:
            newState.goodsInfo = action.response;

        case types.SET_ALL_EXPRESS_COMPANY:
            newState.expressCompany = action.response;

        case types.SET_EXPRESS_COMPANY:
            newState.expressInfo =  {
                trackingNumber: state.expressInfo.trackingNumber,
                shippingId: action.response.shippingId,
                shippingName: action.response.shippingName,
            }
        case types.SET_EXPRESS_STATUS:
            newState.showExpressSuccessModal = action.response;

        case types.INIT_TRACK_NUMBER:
            newState.expressInfo = {
                trackingNumber: action.response,
                shippingId: state.expressInfo.shippingId,
                shippingName:  state.expressInfo.shippingName,
            }
    }

   return newState
}
export default reducers

而action的數(shù)據(jù)格式一般是這樣的:

{
        type: types.SEND_GOODS,
        response: response
    }

連在一起看語(yǔ)句currentState = currentReducer(currentState, action) 是不是好懂很多呢旧巾?將保存在store上的state傳入reducer函數(shù)中耸序,獲得新的state(要復(fù)制一份state的原因還不清楚)
接下來(lái)

const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

那么currentListeners何時(shí)更新?我們接著看一下subscribe函數(shù)鲁猩。

  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.')
    }

    if (isDispatching) {
      throw new Error(
        'You may not call store.subscribe() while the reducer is executing. ' +
          'If you would like to be notified after the store has been updated, subscribe from a ' +
          'component and invoke store.getState() in the callback to access the latest state. ' +
          'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
      )
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
      ....

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

執(zhí)行subscribe函數(shù)坎怪,實(shí)際上就是將回調(diào)函數(shù)加入nextListeners這個(gè)list中,當(dāng)執(zhí)行dispatch時(shí)廓握,nextListeners中每個(gè)listener函數(shù)會(huì)順序執(zhí)行搅窿。這樣就完成了每次store中數(shù)據(jù)發(fā)生變更,subscribe中函數(shù)就會(huì)執(zhí)行一次。至于為什么會(huì)有兩個(gè)變量currentListenersnextListeners來(lái)維持回調(diào)隊(duì)列隙券,還不是很清楚原因男应。

最后提出三個(gè)問(wèn)題:

  • 為什么reduce函數(shù)中中要返回新的state
  • 為什么listener也要保持純凈
  • 為什么react中這么喜歡使用mutual哲學(xué)

后續(xù)更新:

  • observable 由于沒有用過(guò)observable,這部分的源碼先不看。

react-redux源碼分析

  • 如何感知store的變化
  • 如何修改state的變化

redux-thunk源碼分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末娱仔,一起剝皮案震驚了整個(gè)濱河市沐飘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌牲迫,老刑警劉巖耐朴,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盹憎,居然都是意外死亡隔箍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門脚乡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事奶稠「┘瑁” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵锌订,是天一觀的道長(zhǎng)竹握。 經(jīng)常有香客問(wèn)我,道長(zhǎng)辆飘,這世上最難降的妖魔是什么啦辐? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蜈项,結(jié)果婚禮上芹关,老公的妹妹穿的比我還像新娘。我一直安慰自己紧卒,他們只是感情好侥衬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跑芳,像睡著了一般轴总。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上博个,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天怀樟,我揣著相機(jī)與錄音,去河邊找鬼盆佣。 笑死往堡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罪塔。 我是一名探鬼主播投蝉,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼征堪!你這毒婦竟也來(lái)了瘩缆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤佃蚜,失蹤者是張志新(化名)和其女友劉穎庸娱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谐算,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡熟尉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洲脂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斤儿。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剧包,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出往果,到底是詐尸還是另有隱情疆液,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布陕贮,位于F島的核電站堕油,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肮之。R本人自食惡果不足惜掉缺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望戈擒。 院中可真熱鬧眶明,春花似錦、人聲如沸峦甩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)凯傲。三九已至犬辰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冰单,已是汗流浹背幌缝。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诫欠,地道東北人涵卵。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像荒叼,于是被迫代替她去往敵國(guó)和親轿偎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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

  • 使用redux+react已有一段時(shí)間被廓,剛開始使用并未深入了解其源碼坏晦,最近靜下心細(xì)讀源碼,感觸頗深~ 本文主要包含...
  • Redux是React核心開發(fā)人員的開發(fā)的一個(gè)JavaScript 狀態(tài)容器嫁乘,提供可預(yù)測(cè)化的狀態(tài)管理昆婿。 Redux...
    人失格閱讀 859評(píng)論 0 0
  • 1 redux使用步驟 React僅僅是一個(gè)前端View框架庫(kù),可以看做是MVC里面的V蜓斧。沒有解決組件間通信仓蛆,MV...
    Dabao123閱讀 421評(píng)論 0 2
  • 學(xué)習(xí)必備要點(diǎn): 首先弄明白,Redux在使用React開發(fā)應(yīng)用時(shí)挎春,起到什么作用——狀態(tài)集中管理 弄清楚Redux是...
    賀賀v5閱讀 8,902評(píng)論 10 58
  • 咪蒙的公眾號(hào)被關(guān)了,我都不知道能庆,只是當(dāng)網(wǎng)上出現(xiàn)了許多評(píng)論文章一炮而紅時(shí)辽装,我才注意到最新一篇的文章看不到,而之所以不...
    似水若煙閱讀 735評(píng)論 20 8