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

1.png

上集回顧

 

Redux是如何使用的?首先再來回顧一下這個使用demo(誰讓這段代碼完整地展示了redux的使用)

2.jpg

如果有小夥伴對這段代碼不是很理解的話,建議先去學習Redux的使用再來看這篇源碼,這樣更加事半功倍。通過上段代碼,我們拆分幾個比較核心的點,我一一列舉一下:

 

1. action的結構是如何的?

2. 如何去定義一個reducer?

3. combineReducers是如何整合多個reducer的?

4. createStore是如何創建一個store?

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

6. subscribe是如何監聽狀態發生改變的?

7. getState是如何拿到所有的狀態值的?

 

上期我們先解決了前三個疑問,這期我們一起來探索後4個問題。

 

 4、createStore是如何創建一個store?

首先我們先擼一個createStore架構出來:

3.jpg

通過這段代碼我們知道了傳參應該是什麼樣子和返回了什麼。從中我發現了一個問題,createStore接受的是三個參數:1、reducer 2、預加載的state 3、redux-thunk之類的增強器。但是我們平時經常會寫成如下這個樣子:

4.jpg

我們會在第二個參數就傳入了增強器,這跟源代碼的參數結構不符哎,但是爲什麼就可以這麼用了。接下來我們就看一下,reducer是如何做這個處理的。

5.jpg

當第二個參數preloadedState的類型是Function的時候,並且第三個參數enhancer未定義的時候,此時preloadedState將會被賦值給enhancer,preloadedState會替代enhancer變成undefined的。有了這麼一層轉換之後,我們就可以大膽地第二個參數傳enhancer了。

 

解決了這個疑問之後,往下就是解釋一下他返回的值是什麼東西,這些解答我們就放在下面做解釋,這裏就不做贅述了。不過在接下去之前,我們得搞清楚下面這組變量代表啥意思。

6.jpg

其中變量isDispatching,作爲鎖來用,我們redux是一個統一管理狀態容器,它要保證數據的一致性,所以同一個時間裏,只能做一次數據修改,如果兩個action同時觸發reducer對同一數據的修改,那麼將會帶來巨大的災難。所以變量isDispatching就是爲了防止這一點而存在的。

 

 

5、dispatch拿到action到底幹了啥?

7.jpg

函數dispatch在函數體一開始就進行了三次條件判斷,分別是以下三個: 

1.判斷action是否爲簡單對象 

2.判斷action.type是否存在 

3. 判斷當前是否有執行其他的reducer操作

 

當前三個預置條件判斷都成立時,纔會執行後續操作,否則拋出異常。在執行reducer的操作的時候用到了try-finally,可能大家平時try-catch用的比較多,這個用到的還是比較少。執行前isDispatching設置爲true,阻止後續的action進來觸發reducer操作,得到的state值賦值給currentState,完成之後再finally裏將isDispatching再改爲false,允許後續的action進來觸發reducer操作。接着一一通知訂閱者做數據更新,不傳入任何參數。最後返回當前的action。

 

6、subscribe是如何監聽狀態發生改變的?

8.jpg

在註冊訂閱者之前,做了兩個條件判斷:

1. 判斷監聽者是否爲函數 

2.  是否有reducer正在進行數據修改(保證數據的一致性)

接下來執行了函數ensureCanMutateNextListeners,下面我們看一下ensureCanMutateNextListeners函數的具體實現邏輯:

9.jpg

邏輯很簡單,判斷nextListeners和currentListeners是否爲同一個引用,還記得初始變量定義那以及函數dispatch內部那兩處的代碼嗎?

10.jpg

這兩處將nextListeners和currentListeners引用了同一個數組,而ensureCanMutateNextListeners就是用來判斷這種情況的,當nextListeners和currentListeners爲同一個引用時,則做一層淺拷貝,這裏用的就是Array.prototype.slice方法,該方法會返回一個新的數組,這樣就可以達到淺拷貝的效果。

 

函數ensureCanMutateNextListeners作爲處理之後,將新的訂閱者加入nextListeners中,並且返回取消訂閱的函數unsubscribe。函數unsubscribe執行時,也會執行兩個條件判斷:

1. 是否已經取消訂閱(已取消的不必執行)

2. 是否有reducer正在進行數據修改(保證數據的一致性)

 

通過條件判斷之後,將該訂閱者從nextListeners中刪除。看到這裏可能有小夥伴們對currentListeners和nextListeners有這麼一個疑問?函數dispatch裏面將二者引用同一個數組,爲啥這裏將二者分別引用兩個值相同的數組?直接用currentListeners不可以嗎?這裏這樣做其實也是爲了數據的一致性,因爲有這麼一種的情況存在。當redux在通知所有訂閱者的時候,此時又有一個新的訂閱者加進來了。如果只用currentListeners的話,當新的訂閱者插進來的時候,就會打亂原有的順序,從而引發一些嚴重的問題。

 

 7、getState是如何拿到所有的狀態值的?

11.jpg

getState相比較dispatch要簡單許多,返回currentState即可,而這個currentState在每次dispatch得時候都會得到響應的更新。同樣是爲了保證數據的一致性,當在reducer操作的時候,是不可以讀取當前的state值的。

看完是不是已滿腔熱血

充滿了鬥志?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章