書籍完整目錄
1.6 flux
這一節將介紹 React 的核心應用架構模式 Flux,包括內容:
-
Flux 介紹
-
MVC 架構之痛
-
Flux 的理解
-
Flux 相關庫和工具介紹
-
Flux 與 React 實例
最後我們將會把之前的 TODOMVC 改為 Flux 的架構。
1.6.1 Flux 介紹
簡單來講,Flux 是 Facebook 引入到 React 中的一種前端架構,通過定義其核心單向數據流的方式,讓 React 應用更加健壯。同時,這種應用架構也具有普適性,可以應用到其他任意前端項目中,甚至可以應用到客户端應用開發中,也就是説 Flux 更應該叫做一種架構模式(Pattern)。
1.6.2 MVC 架構之痛
在詳細介紹 Flux 之前,我們先來看看傳統的前端 MVC 架構以及其帶來的問題。
MVC 的實現可能有很多種方式,比較靈活,但基本本質不會改變,只是三者間的數據傳遞方向可能會改變,即便是 MVP 模式也只是 MVC 的變種,所以為了統一我們且以下圖的 MVC 方式來討論。
概念
-
Model: 負責保存應用數據,和後端交互同步應用數據
-
View: 負責渲染頁面 HTML DOM
-
Controller: 負責連接 View 和 Model , Model 的任何改變會應用到 View 中,View 的操作會通過 Controller 應用到 Model 中
-
關係:Model, View, Controller 都是多對多關係。
流程
以 TODOMVC 為例子用户添加一個 todo 的交互流程:
View -> Action -> Controller -> Model -> View
-
View -> Action: 添加按鈕事件或者 input 輸入的提交事件
-
Action -> Controller: 控制器響應 View 事件
-
Controller -> Model: 控制器依賴 Model, 調用 Model 添加 todo
-
Model -> View: View 監聽 Model 的改變添加 todo 事件,在 HTML 中添加一個新的 Todo 視圖
問題
對於新增一個 todo ,需要編寫一個視圖渲染處理函數,函數內添加新項目到列表中。同理對於刪除一個 todo,也會有一個處理函數。當業務邏輯變多過後,可能有很多模型需要做增刪改的功能,與之對應的就是我們需要精心構建這麼多的渲染處理函數。 這種局部更新模式是高性能的關鍵所在,但問題是:
-
更新邏輯複雜,需要編寫大量的局部渲染函數
-
問題定位困難,頁面的當前狀態是有數據和這些局部更新函數確定的
如何解決
如果渲染函數只有一個,統一放在 App 控制器中,每次更新重渲染頁面,這樣的話:
-
任何數據的更新都只用調用重渲染就行
-
數據和當前頁面的狀態是唯一確定的
重渲染也有弊端,會帶來嚴重的性能問題,重渲染和局部渲染各有好壞,對 MVC 來説這是一個兩難的選擇,無法做到魚和熊掌兼得。
那如何才能兼顧兩種模式的優點?
1.6.3 Flux 架構
通過 React + Flux 就可以完美解決 MVC 的問題。
-
重渲染: 在 React 中每次渲染都是重渲染,且不影響頁面性能,是因為重渲染的是 Virtual Dom。這就意味着完全不用去關係重渲染問題,增刪改的渲染都和初始化渲染相同入口
-
數據和狀態一致性: Store 的數據確定應用唯一的狀態
簡單來説在 Flux 架構中直接剝離了控制器層,MVC 架構變成了 MV + Flux 架構。
概念
單向數據流
這是 Flux 架構的核心思想,重上面的圖中可以看到,數據的流向從action 到 view 的一個單向流。
Action
Action 可以理解為對應用數據修改的指令,任何修改應用數據的行為都必須需通過觸發 action 來修改。Action 可以來自於 View,也可以來自服務端的數據更新。
Action Creator:
為了抽象 Action ,提供一些輔助的語義化的方法來創建 Action,這些輔助方法叫做 Action Creator。
Stores
應用的數據中心,所有應用數據都存放在這裏控制,同時包含數據的控制行為,可能包含多個 store
Dispatcher
action 的控制者,所有 action 都會通過 dispatcher,由 dispatcher 控制 action 是否應該傳入到 store 中,Dispatcher 是一個單例。
View
頁面的視圖,對應 React 的 Component, 視圖可以觸發 action 到 dispatcher。
需要區別出一種叫控制器 View(Controller View)的類型,這種 View 可以知曉 store 數據,把 store 數據轉化為自身的狀態,在將數據傳遞給其他 view 。 並且可以監聽 store 數據的改變,當 store 數據改變過後重新設置狀態觸發重渲染。 可以將控制器 View 對應 MVC 中的控制器,但是差別很大,控制器 View 唯一多做的事情就是監聽 store 數據改變,沒有其他任何業務處理邏輯。
流程
同樣以 TODOMVC 的添加 todo 為例,Flux 中的流程為:
View -> Action(Action Creator -> Action) -> Dispatcher -> Store -> Controller View -> View
-
View -> Action: 添加按鈕事件或者 input 輸入的提交事件,View 中將事件轉化為 action, action 由 Action Creator 創建。
-
Action -> Dispatcher: action 統一由 Dispatcher 分配
-
Dispatcher -> Store: Dispatcher 分配 action 到 Store
-
Store -> Controller View: 控制器 View 監聽 store 的數據改變,將數據轉化為自身屬性
-
Controller View -> View: 數據改變自動重渲染所有視圖
對比
-
渲染策略: 數據改變 Flux 自動渲染,MVC 手動編寫更新函數
-
事件觸發策略: Flux 中所有 action 交給 dispather 分配,MVC 中交給對應的控制器分配
Flux 在核心策略上的不同是解決 MVC 架構問題的關鍵
1.6.4 理解 Flux 架構
Flux 架構是非常優雅簡潔的,合理利用了一些優秀的架構思維
分而治之(Divide And Conquer)
數據的處理過程是 Store -> Controller View -> View。 所有數據來自於 Store,頁面的渲染層級為 Store 將數據傳入 Controller View, 再由 Controller View 傳入子 View , 一直到 View 的葉子節點。
這個是一個典型的分而治之策略,將大的頁面拆分為小的模塊,再由小的模塊拆分為小的組件,具體組件負者組件自身的問題,所有子組件都是自私的,不用關心“大家”,只用關心“小家”。
合而治之 - 中心化控制
Flux 把所有的 View 都視作愚民,Store 視作資源的擁有者為統治者,統治者需要提供資源(數據)給平民,但是如果平民企圖對資源修改(Mutation),必須得先通知給統治者,讓統治者決定是否做處理。
我們為 Flux 中的概念分配角色
-
View: 平民
-
Action: 資源修改操作
-
Dispatcher: 審核官
-
Store: 統治者
一個企圖修改資源的操作可以描述為:
View Require Mutation -> Action -> Dispatcher -> Store -> Mutate Handler
平民提交 Mutation 請求,由審核官控制,審核通過後遞交給統治者,統治者再分配給親信做資源 Mutation
合而治之的策略也等於中心化控制策略, 作為統治者既要懂得放權利(資源的分配),也要懂得控制權利(資源的修改),這種收縮自如的合理性是 Flux 簡潔的根本。
同時這種思維帶來的優點如下:
-
View 的獨立性和簡單性:View 自身的邏輯簡單,不需要知道太多事情,只關心上級傳來的數據,這種模式使得 View 是低耦合的,簡潔的。
-
高可維護性:中心化控制知道所有對資源的操作,如果發生 bug, 可以很快定位問題
函數式編程思想
在 Flux 中數據的單向流動依賴於 View 的確定性,相同的數據傳入相同的組件,得到的結果必然要相同,這是函數式編程的思想。
函數式編程中的純函數(Pure Function)定義如下:
純函數是這樣一種函數,即相同的輸入,永遠會得到相同的輸出,而且沒有任何可觀察的副作用
如:
// 純函數,相同的輸入必定有相同的輸出
function pure(a, b, c) {
return a + b + c;
}
// 非純函數,我們永遠無法確定 this.a 會變成什麼
function notPure(b, c) {
return this.a + b + c;
}
為了保證組件也能做到 “純函數” 的特性,相同的屬性會得到相同的渲染結果。 在寫 React 組件的時候儘量準守一下約定:
-
儘量使用無狀態組件
-
除了控制類組件以外其他組件避免使用組件狀態
-
可以通過屬性計算出來的狀態不要用狀態來表示
-
組件的渲染避免外部依賴,按照純函數的方式寫
函數式的優點也是無副作用組件的優點:
-
無耦合,可移植性強: 組件可重用性高
-
可測試性高:組件無依賴,可以很容易的單獨測試組件
1.6.5 Flux 生態
上面已經講過 Flux 更應該算是 Facebook 提出的一種前端架構模式,而根據這種理念的 Flux 實現有很多,以下是 github star 數較高的一些實現:
-
Facebook 官方實現
-
Redux 目前認可度最高的實現
-
refluxjs
-
alt
-
fluxxor
後面我們會在第四章中專門講解 Redux 與 React 的應用。
1.6.6 Flux 與 React 實例
@todo