技本功丨知否知否,Redux源碼竟如此意味深長(上集)

圖片描述

夫 子 說redux

圖片描述

元月二號欠下袋鼠雲技術公號一篇關於Redux源碼解讀的文章,轉眼月底,期間常被「債主」上門催債。因爲年末項目工期比較緊,因而債務就這樣被利滾利。可是好在這段時間有點閒暇,因而趕忙把這篇文章給完成了。聽說文章點贊多了能夠抵扣利息,小夥們要是以爲我這篇文章還不錯的話,記得幫我點贊哦!好讓我早日擺脫債務,感激涕零!函數

圖片描述

好了,回到正題。今天打算和你們講一講redux的源碼,經過分析源碼,我我的以爲受益不淺,藉此經過這篇文章把個人一些心得體會向你們分享一下,另外須要注意一下此次分享的源碼用的redux的V4.0.0版本,小夥伴在對照的時候可別搞錯咯。接下來老司機但是要發車了,你們抓緊時間上車哦!學習

圖片描述

在講源碼以前咱們首先回顧一下redux是如何使用的,下面咱們看一下使用demo:spa

圖片描述

上面這段代碼完整地展現了redux的使用(若是有小夥伴對這段代碼不是很理解的話,建議先去學習redux的使用再來看這篇源碼,這樣更加事半功倍)。經過上段代碼,咱們拆分幾個比較核心的點,我一一列舉一下:代理

  1. action的結構是如何的?
  2. 如何去定義一個reducer?
  3. combineReducers是如何整合多個reducer的?
  4. createStore是如何建立一個store?

5.dispatch拿到action到底幹了什麼?對象

  1. subscribe是如何監聽狀態發生改變的?
  2. getState是如何拿到全部的狀態值的?

本期先解決前三個疑問,讓咱們一塊兒去源碼裏尋找答案!圖片

一、action的結構是如何的?開發

首先得解釋一下action是幹嗎的,它是負責把數據從應用帶到store裏面,也是store的惟一數據來源,並由如下兩個部分組成:get

  1. type (操做類型)
  2. payload (攜帶的數據)

爲何得有這兩個?其實也很好理解,咱們拿銀行來類比。某天,你拿着一萬塊來到銀行,走到櫃檯,人業務員第一件事確定是問你要辦啥業務,存錢?轉帳?仍是還貸?你得把這些告訴業務員,否則業務無法給你辦理業務,所以咱們action就得有一個type,好讓reducer知道你要幹啥。固然,你辦理存款或者是還款啥的,必不能少的就是毛爺爺了,payload對應的值就比如這些毛爺爺。用一個話來總結action的做用就是:告訴reducer拿着payload去作type這件事。input

二、如何去定義一個reducer?

上面講action的時候,提到了reducer了,這裏仍是拿我上面的銀行作個類比,當咱們拿着錢去銀行存錢,咱們不可能本身去銀行把銀行保險櫃打開,完了把錢放進去,這樣是不容許的,咱們得須要業務員這個中間人去幫咱們作存錢這件事,而業務員所扮演的角色正好就是reducer所要擔任的角色。接下來說一下如何去定義一個reducer,其實reducer的寫法並無絕對的寫法,只要符合下面幾個條件都能稱之爲reducer:

  1. 必須得是一個函數。
  2. 函數接收兩個參數。第一個:該reducer所負責的state。第二個:action。
  3. 函數體內部能夠針對不一樣的action的type作出響應,這裏你能夠if-else或者switch-case都是能夠的。
  4. 函數必須有返回值。當修改state了以後,必須將修改後的state返回。若是遇到未知的type則須要返回一個默認值。

三、combineReducers是如何整合多個reducer的?

咱們先看一下combineReducers傳入的參數:

圖片描述

combineReducers接受的是一個參數首先得是對象,其次該對象每個屬性對應一個reducer。搞清楚combineReducers的結構以後,咱們再看一下combineReducers對其作了哪些處理。

第一步:淺拷貝reducers

圖片描述

這裏定義了一個finalReducers和finalReducerKeys,分別用來拷貝reducers和其屬性。先用Object.keys方法拿到reducers全部的屬性,而後進行for循環,每一項可根據其屬性拿到對應的reducer,並淺拷貝到finalReducers中,可是前提條件是每一個reducer的類型必須是Function,否則會直接跳過不拷貝。

第二步:檢測finalReducers裏的每一個reducer是否都有默認返回值

圖片描述

assertReducerShape方法主要檢測兩點:

  1. 不能佔用redux內部特有的命名空間
  2. 若是遇到未知的action的類型,reducer不能返回undefined,得返回默認的值

若是傳入type爲 @@redux/INIT<隨機值> 的action,返回undefined,說明沒有對未 知的action的類型作響應,須要加默認值。若是對應type爲 @@redux/INIT<隨機值> 的action返回不爲undefined,可是卻對應type爲 @@redux/PROBE_UNKNOWN_ACTION_<隨機值> 返回爲undefined,說明佔用了 命名空間。整個邏輯相對簡單,好好本身梳理一下。

第三步:返回一個函數,用於代理全部的reducer

圖片描述

先對傳入的state用getUnexpectedStateShapeWarningMessage作了一個異常檢測,找出state裏面沒有對應reducer的key,並提示開發者作調整。接着咱們跳到getUnexpectedStateShapeWarningMessage裏,看其實現。

圖片描述

getUnexpectedStateShapeWarningMessage接收四個參數inputState(state)、reducers(finalReducers)、action(action)、unexpectedKeyCache(unexpectedKeyCache),這裏要說一下unexpectedKeyCache是上一次檢測inputState獲得的其裏面沒有對應的reducer集合裏的異常key的集合。整個邏輯以下:

  1. 前置條件判斷,保證reducers集合不爲{}以及inputState爲簡單對象
  2. 找出inputState裏有的key可是 reducers集合裏沒有key
  3. 若是是替換reducer的action,跳過第四步,不打印異常信息
  4. 將全部異常的key打印出來

getUnexpectedStateShapeWarningMessage分析完以後,咱們接着看後面的代碼。

圖片描述

首先定義了一個hasChanged變量用來表示state是否發生變化,遍歷reducers集合,將每一個reducer對應的原state傳入其中,得出其對應的新的state。緊接着後面對新的state作了一層未定義的校驗,函數getUndefinedStateErrorMessage的代碼以下:

圖片描述

邏輯很簡單,僅僅作了一下錯誤信息的拼接。未定義校驗完了以後,會跟原state做對比,得出其是否發生變化。最後發生變化返回nextState,不然返回state。

未完待續

下期預告

《技本功丨知否知否,Redux源碼竟如此意味深長(下集)》

THE END

最後,袋萌萌感謝每一位老鐵2018年的陪伴,生死看淡,不服就幹!2019,我們再戰,不斷進步!

圖片描述

相關文章
相關標籤/搜索