1. 程式人生 > >筆記----深入淺出《React和Redux》第三章Flux框架

筆記----深入淺出《React和Redux》第三章Flux框架

書中的此章節“思想”類成分較多,需要理解的內容也相對較多,如果一一列舉,本文就寫的相對繁瑣了,推薦有興趣的同學可以去看一下書籍以及敲一下書中的程式碼,有助於理解作者大牛的思想,我就在此簡略的記錄一些相對重要的“點”了。

 

一、Flux框架的誕生以及解決了MVC框架哪些問題

  1、Flux出現背景

      Facebook的工程部門發現在前端使用MVC框架進行邏輯劃分時,在業務量和程式碼量龐大的情況下,model層和view層之間依賴過於複雜,不利於後期對於程式碼的維護

      

   理想中,各個模組分工:

   Model:負責邏輯以及資料

       View:負責渲染介面

       Controller:負責接收使用者的輸入,根據使用者的輸入呼叫對應的Model部分邏輯,把產生的資料結果交給View部分,讓View渲染出必要的輸出

 

   MVC框架的請求流程:使用者請求------>Controller------>Model------>View,View和Model不能直接進行互相通訊,都需要藉助於Control

  

 

  

  在實際工作中,對於瀏覽器端 MVC 框架,存在使用者的互動處理,介面渲染出來之後,Model 和 View 依然存在於瀏覽器中,這時候就會誘惑開發者為了簡便,讓現存的 Model和 View直接對話,當代碼量和邏輯複雜時,使程式“脆弱而且不可預測”

 

  2、Flux框架

   

   (1)特點:更嚴格的資料流控制

 

       (2)各個模組:

             Dispatcher(相當於“Controller”):用來接收Actions、執行回撥函式;

     Store(相當於“Model”):用來存放應用的狀態,一旦發生變動,就提醒Views要更新頁面;

     Action(相當於“使用者請求”):檢視層發出的訊息;

             View:顯示使用者介面;

 

  (3)與MVC框架的區別:

    (i)當系統需要擴充應用所能處理的“請求”時,在MVC中,通過在Controller增加函式,來實現擴充;

               在Flux中,不需要Dispatcher增加新函式,而是通過增加新的Action型別,來實現擴充

 

  (4)Flux實踐 (直接上程式碼)

 

    實現的效果:

       

        

                   當點選“+”按鈕或者“-”按鈕,對應行的數字會時時進行改變,並且總數也會時時改變,下圖:

      

      

 

 

              步驟一

        安裝Flux:npm install --save flux             (如果感覺慢,可以安裝國內淘寶映象)

       

       (i)Dispatcher

                     

       作用:生成Dispatcher例項,用來之後將 Action 派發到 Store

       注意!注意! 注意!Dispatcher例項在全域性只有一個

 

      (ii)Action(分2個檔案,一個定義action型別,另一個定義action建構函式)

        ActionTypes.js

        

        說明:將常量放在單獨一個檔案方便管理

 

        Actions.js 

        

        作用:根據型別,生成不同的action物件,通過Dispatcher例項的dispatch函式派發出去

        注意:出於業界習慣,這個檔案被命名為Actions.js,但是要注意裡面定義的並不是action物件本身,而是能夠產生並進行派發action物件的函式 

                        

       (iii)Store(建立了兩個store,CounterStore是為Counter元件服務,SummaryStore是為總數服務)

        CounterStore.js

         

         

        說明:在CounterStore中可以看出,首先定義了Counter元件初始化的值,然後使用Object.assgin()函式,對EventEmitter.prototype物件進行了淺拷貝,並在此淺拷貝物件的基礎上擴充了getCounterValues、emitChange、addChangeListener、removeChangeListener方法。其中這四個方法的後三個方法,分別呼叫了EventEmitter.prototype的on(),emit(),removeListener()方法,作用如下:

         on(EVENT_TYPE,callback):用來監聽事件,第一個引數是字串事件型別,第二個引數是事件處理函式;

         emit(EVENT_TYPE):用來觸發事件,第一個引數是字串事件型別;

         removeListener(EVENT_TYPE,callback):用來移除事件,如果要呼叫removeListener函式,就一定要保留對處理函式的引用,

                                                                                       第一個引數是字串事件類型,第二個引數是事件處理函式。

最後,通過把AppDispatcher.register()中的回撥函式註冊到Dispatcher上,來接受之前通過AppDispatcher.dispatch()派發的action物件,通過switch或if-else來實現對應型別的動作實現對應型別的操作。

        

        

 

        SummaryStore.js

         

         

        說明:總體程式碼和之前CounterStore差不多。需要說明的是在這兩個store中,AppDispatcher.register()會返回一個標記,儲存在各自store的dispatchToken欄位中,用來之後實現多個store之間行為的依賴順序,藉助waitFor()。在這個程式碼中,我們希望SummaryStore的邏輯在CounterStore之後進行

 

  

        作用: Store是一個物件,既用於儲存應用狀態,也用來接受Dispatcher派發的動作,根據動作決定是否更新應用狀態。

 

        注意:store 在Flux中可以存在多個,每一個 store 都會受到所有的 action 通知,然後自行覺得是否對這個 action 做出響應,更新 state;

             store對外只暴露了讀取介面,如果想實現寫入的功能,只能去實現對應action。

 

     

        (iv)View(用React進行實現,3個檢視元件,其中ControlPanel父元件包含Counter子元件,Summary子元件)

        

         ControlPanel元件

        

 

        Counter

                

          

 

         Summary

         

        View 的程式碼就是常規React書寫方式,就不一一敘述了

 

         注意:存在於Flux框架中的React元件需要實現以下幾個功能

              1)建立時要讀取Store上的狀態來初始化元件內部狀態;(而不像之前通過props傳參,實現元件內部初始化)

            2)當Store上狀態發生變化時,元件要立刻同步更新內部狀態保持一致;(通過Store改變狀態後呼叫emit(),以及View通過on()來監聽Store中狀態的變化)

            3)View如果要改變Store狀態,只能派發action。(Flux中,對Store進行修改,只能通過新建action)

 

 

        (v)上述程式碼個人理解及總結:

    過程一:按著元件的生命週期函式順序,進行渲染。其中componentDidMount函式通過CounterStore.addChangeListen函式監聽了CounterStore的變化之後,只要CounterStore發

                         生變化,Counter元件的onChange函式就自動會被呼叫。不過首次掛載時,可以發現getCounterValue被重複呼叫了2次來讀取相同值,分別是第一個是constructor中被調

                         用,第二個是componentDidMount中的this.onChange中被呼叫

              

              

                  

   

    過程二:當進行點選“+”按鈕時,this.props.caption立即讀取了當前元件上的屬性值First,以形參的形式傳入increment()方法,並觸發increment();

              (以First為例子)         

                  

 

    過程三:此時Dispatcher的例項(AppDispatcher)呼叫dispatch()方法,將剛產生的action物件派發出去,此時action物件上攜帶著動作型別,以及剛剛傳入的First字串標記

                           

 

    過程四: 通過AppDispatche.register()來註冊回撥函式,之後這個回撥函式就可以接受派發出來的action物件,並根據這個action物件的型別,執行對應的邏輯,即在這裡的邏輯是根

                        據action.counterCaption拿到First,然後通過counterValues[First]拿到當前儲存在Store中的初始值,並進行加一操作,最後通過emit(),將事件觸發

                        

             

 

        過程五:在過程一首次掛載時,onChange函式作為形引數,最終傳入on()中,監聽事件的觸發,也就是等待emit函式被呼叫,然後執行onChange函式內部操作,通過

                                    getCounterValues獲得Store的新狀態值,即First欄位加一後的值,最後通過setState函式將這個值同步到元件內部狀態count上,同時State的更新會觸發生命週期    

            的shouldComponentUpdate函式,判斷此次渲染是否與上一次不同,如果不同則返回true,並將結果渲染到頁面 

            

             

                        

 

             其他的“-”按鈕以及計算總和的步驟流程也差不多,我就不繼續進行描述了,可以按照上面過程進行推演。 

 

            結合自己理解,畫了一個圖,完畢。

            

            睡覺睡覺!!!!!!!

 

 

其他參考:http://www.ruanyifeng.com/blog/2016/01/flux.html