【React系列】從零開始入門Redux

       我在學習redux的時候,一開始也以爲很難,不少東西很難以理解,由於我是先簡單學習了一遍Vue的,由於工做中用的都是react,因此Vue也忘得差很少了。寫這篇文章的緣由是想幫助想入門react的小夥伴們,同時也是對本身的一個技術小總結吧。前端

       react難就難在它很自由,就提供了一個JSX,而後就沒有了。不過和當初React的定位也有關係,它並非一個框架,而是一個UI庫。而Vue纔是一個框架,由於不少事情它都幫你完成了,使用的時候僅須要知道相關的API。react

       tips:能夠這麼粗淺的理解react,UI = fn(data)git

好了扯遠了,下面開始帶你入門redux吧。github

redux

       首先,在學習以前,要說明一點,react和redux沒有任何關係,沒有任何關係,沒有任何關係;重要的事情說三遍。那redux是什麼呢?是一個管理數據的倉庫。編程

爲何須要redux呢?

      緣由是由於前端數據的複雜度沒有人來管理,由於react當初的定位也是爲了解決中大型項目,項目一旦複雜起來,須要共享的數據就會很龐大複雜。redux

redux的核心概念

      在介紹核心概念以前,咱們先來了解一個東西,就是Flux。在Flux中,Facebook最先提出了一個action的概念,經過action來直接修改數據倉庫store,action是一個普通的對象,用於描述要幹什麼。store根據不一樣的action來對數據進行操做。數組

      這樣就會有一個問題,當業務複雜,數據龐大的時候,store的壓力就不少了,因此纔有了後面redux的出現,到這裏,你只須要知道redux的三個核心概念就能夠了。app

      action:至關於頁面請求等操做,分發dispatch框架

      reducer:數據的控制器,數據的修改者,就是修改數據的

      store:數據的倉庫函數式編程

redux是如何工做的?


第一步:首先action是一個平面對象,就是一個簡單的對象,必需要傳type屬性,類型任意,表明着你要幹什麼,還有一個可選屬性是payload,就是請求時候的附加數據。

第二步:store接收到action的請求以後,把舊的數據state,和請求action交給reducer,讓reducer來修改數據,修改完以後返回一個新的數據newState給我,以便更新數據。

       明白了上圖描述的redux工做流程以後,咱們須要建立一個store,由於根據上圖,不論是接收action,或者是觸發reducer修改數據,都是根據數據倉庫的,全部咱們先要建立一個數據倉庫。直接看下面代碼和註釋吧。

createStore

       createStore 返回值是一個對象,對象包含如下幾個屬性

       dispatch:分發一個action,天然要接收一個action參數

       getState:獲得當前的state數據

       subscribe:訂閱一個監聽器,分發action的時候自動會執行,訂閱時候返回一個函數,方便取消訂閱。

       Symbol('observable'):提案,暫時用不到

tips:到這裏,熟悉發佈訂閱模式的小夥伴,就知道其實 createStore 內部的代碼原理就是使用了發佈訂閱模式。不熟悉發佈訂閱模式的小夥伴須要去了解一下。

代碼


接着咱們把action和reducer完善好


最後咱們就可使用了,結合上圖的兩個步驟理解


tips:最好本身手動實現一遍代碼,而後按照redux工做原理兩大步驟圖理解一下。

bindActionCreators

       根據上面redux的工做流程,有沒有發現太麻煩了?的確是太麻煩了,尤爲是第二步,要本身主動去使用store.dispatch,而後再往裏面塞action的平面對象。那有沒有方便一點的方法呢?redux提供了一個函數,bindActionCreators,加強action建立函數,讓action以後自動觸發dispatch。

/**
* bindActionCreators,加強action,自動dispach。
* 接受兩個參數
* 第一個是actions,若是是函數,返回一個函數,若是是對象,返回一個對象
* 第二個dispach,actions須要加強的函數
*/

代碼


使用起來就至關簡單了,下面作一個對比


combineReducers

       如今還有一個問題,就是倉庫數據只有一個,只有一個reducer,而在實際的項目中,數據是很龐大的,有不少個reducer,那怎麼來管理這麼多數據呢?


代碼

咱們能夠先這樣解決問題


其實redux很貼心,爲我麼提供了至關於上面效果的一個函數,就是 combineReducers。

/**
* 組裝reducers, 返回一個reducer,數據使用一個對象表示,
* 對象的屬性名與傳遞的參數對象保持一致
* 返回的是一個總的 reducer函數
*/


完善 validiteReducers 函數


使用的時候,只須要簡單的導出 combineReducers 的運行結果便可,由於它返回一個總的reducer函數,能夠對比一下不使用combineReducers的時候。


middleware

       如今咱們基本上算是完成了一個簡陋版的redux,可是在實際的業務開發中,每每須要請求數據,打印日誌之類的不少附加功能,咱們就舉一個簡單的例子。如今有一個需求,我要打印舊數據和新數據。首先咱們分析一下需求,結合redux的工做流程,咱們知道,action必須返回一個沒有反作用的平面對象,reducer必須是一個純函數。何況action只能拿到舊數據,reducer也不行,觀察發現createStore裏面的能夠拿,那隻能在裏面作手腳了。怎麼作手腳呢?又不能影響原來的功能。

代碼

機智的咱們能夠先這樣作


其實這個就是middleware中間件的原理。並且,中間件如何運用在redux上?總不能像上面這麼low的寫法吧?別急,咱們一步步慢慢分析,理清楚下面這些概念

/**
* 什麼是中間件?
* 中間件,像插件,能夠不影響本來功能、而且不改動本來代碼的基礎上,對其功能進行加強。
* 在redux中,主要是加強dispatch函數
*
* 原理:更改倉庫中的dispatch函數
* 1.先用一個變量保存原來的引用,而後徹底改寫了原來的函數。
* 2.在新改寫的函數中加強咱們須要的功能以後再運行一下原來的函數。
* 3.這樣就達到了目的了
*
* 如何書寫?
* 1.中間件自己是一個函數,該函數接受一個store參數,表示建立的倉庫
* 2.該倉庫並不是一個完成的倉庫,僅包含getState, dispatch
* 3.該函數等倉庫建立完運行
* 4.因爲建立倉庫後須要自動運行設置的中間件函數,所以須要在建立倉庫時,告訴倉庫有哪些*    中間件
* 5.須要調用applyMiddleware函數,將函數的返回值做爲createStore的第二或第三參數
*
* 6.中間件函數必須返回一個函數,用來建立dispatch函數
*/

先看第五點,要使用中間件,必須調用applyMiddleware函數,將函數的返回值做爲createStore的第二或第三參數,來告訴倉庫,咱們建立倉庫的時候,要使用中間件。假設咱們有下面三個中間件,建立倉庫的時候調用applyMiddleware函數。applyMiddleware函數會倒着來運行每一箇中間件。在這裏你能夠先無論它爲何倒着來,先忽略。


而後用代碼來寫一遍,先書寫三個中間件。


而後使用中間件


applyMiddleware

到這裏,你可能會問applyMiddleware爲何要倒着來運行全部的中間件,這和代碼的運行邏輯有關,下面咱們就來解析一下applyMiddleware是怎麼來把全部的中間件運行起來的。在介紹applyMiddleware前,咱們先來認識一下compose,它是函數組合, 函數式編程中的聲明式編程,其實就是把全部的函數的功能組合到一塊兒。

compose

其實能夠簡單的理解成,把全部函數的功能組合成一個函數,就是compose。


有了compose以後,咱們就能夠實現applyMiddleware的原理了,以下代碼


到這裏,咱們就知道爲何applyMiddleware一開始調用的時候是反過來的了。compose函數式編程的魔法,真香!!!

/**
* 爲何applyMiddleware一開始調用的時候是反過來的呢?
* 由於applyMiddleware以後,dispatch纔會運行,這時候纔是正向運行,
* 若是一開始不倒着來,獲得的結果是倒着的喔!!!
* 在中間件中,若是不調用next,就不會調用下一個中間件。
* 這樣的好處就是本身完成本身的事件了,無論你有幾個中間件。
*/

至此,三個中間件就會運用在建立函數裏面了,這也是爲何建立函數的第二個參數能夠傳中間件或者默認值,createStore的完整代碼應該是這樣的。

只看上面的代碼確定很羞澀難懂,結合下面的圖片看纔好理解


其實redux用applyMiddleware使用中間件就是一個洋蔥模型,用到切洋蔥(redux)的時候真想哭(學redux),吃洋蔥(react+redux)的時候,真香。


redux-thunk【擴展】

咱們在寫業務代碼的時候,經常須要AJAX請求數據回來才渲染界面, 若是用redux請求數據,我又堅持要放在action呢?該怎麼請求呢?咱們知道,action必須返回一個沒有反作用的平面對象,不行,怎麼辦呢? redux-thunk 中間件就是專門處理帶有反作用的action的

/**

* redux-thunk 中間件,處理反作用, 通常放在第一個。(後面解釋)
* 怎麼處理反作用呢?他是處理action的反作用的。
* action 必須是一個平面的對象,沒有任何的反作用,可是有了thunk以後,
* 它可讓 action 變成一個函數,容許有反作用。當 action 是一個函數被分發時,
* thunk 會阻止 action 繼續向後移交。要繼續dispatch才日後移交,
* 這樣的話就能夠在裏面處理不少反作用了,好比AJAX請求等等。
* thunk會向函數中傳三個參數:
* dispatch:store.dispatch (爲了從新走一次流程)
* getState: store.dispatch (能夠獲取數據)
* extra:用戶設置的額外參數 thunk.withExtraArgument(123), 使用中間件的時候配置下去。
*/

代碼


那爲何要放在第一個呢?


tips:再仔細想下整個流程,最後跟着思路碼一邊。

thunk源碼


connect

前面咱們都是在講redux怎麼管理數據,那咱們的組件怎麼使用數據呢?

假設咱們都定義好了action、reducer,而且建立好了store。

那麼接下來咱們能夠這樣拿到數據(Users組件拿),直接定義兩個方法,把須要的數據映射進去。


仔細看mapStateToPropsmapDispatchToProps。咱們把須要的數據直接經過導入store,傳進去就完事了。同時訂閱一下this.setState就能夠完成改變數據就刷新界面的效果。

redux仍是很貼心的,哪裏麻煩就出哪裏的API,這時候就可使用react-redux中的 connect 方法了。首先你要理解下面的筆記,或者能夠直接去看相關的API文檔。


有了connect以後代碼就能夠變得很簡單了。直接導出就完事了


總結

       redux其實使用不難,可是理解原理,解析原理代碼是很是繞的,必定要多寫幾遍代碼理解才能真的學會使用redux。

       這裏提供我學習redux源碼的全部代碼筆記,有興趣的小夥伴能夠clone下來研究學習。

github:github.com/huangruitia…

相關文章
相關標籤/搜索