博客 / 詳情

返回

精益 React 學習指南 (Lean React)- 1.6 Flux

書籍完整目錄

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

  1. View -> Action: 添加按鈕事件或者 input 輸入的提交事件

  2. Action -> Controller: 控制器響應 View 事件

  3. Controller -> Model: 控制器依賴 Model, 調用 Model 添加 todo

  4. Model -> View: View 監聽 Model 的改變添加 todo 事件,在 HTML 中添加一個新的 Todo 視圖

問題

對於新增一個 todo ,需要編寫一個視圖渲染處理函數,函數內添加新項目到列表中。同理對於刪除一個 todo,也會有一個處理函數。當業務邏輯變多過後,可能有很多模型需要做增刪改的功能,與之對應的就是我們需要精心構建這麼多的渲染處理函數。 這種局部更新模式是高性能的關鍵所在,但問題是:

  1. 更新邏輯複雜,需要編寫大量的局部渲染函數

  2. 問題定位困難,頁面的當前狀態是有數據和這些局部更新函數確定的

如何解決

如果渲染函數只有一個,統一放在 App 控制器中,每次更新重渲染頁面,這樣的話:

  1. 任何數據的更新都只用調用重渲染就行

  2. 數據和當前頁面的狀態是唯一確定的

重渲染也有弊端,會帶來嚴重的性能問題,重渲染和局部渲染各有好壞,對 MVC 來説這是一個兩難的選擇,無法做到魚和熊掌兼得。

那如何才能兼顧兩種模式的優點?

1.6.3 Flux 架構

通過 React + Flux 就可以完美解決 MVC 的問題。

  1. 重渲染: 在 React 中每次渲染都是重渲染,且不影響頁面性能,是因為重渲染的是 Virtual Dom。這就意味着完全不用去關係重渲染問題,增刪改的渲染都和初始化渲染相同入口

  2. 數據和狀態一致性: 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

  1. View -> Action: 添加按鈕事件或者 input 輸入的提交事件,View 中將事件轉化為 action, action 由 Action Creator 創建。

  2. Action -> Dispatcher: action 統一由 Dispatcher 分配

  3. Dispatcher -> Store: Dispatcher 分配 action 到 Store

  4. Store -> Controller View: 控制器 View 監聽 store 的數據改變,將數據轉化為自身屬性

  5. Controller View -> View: 數據改變自動重渲染所有視圖

對比

  1. 渲染策略: 數據改變 Flux 自動渲染,MVC 手動編寫更新函數

  2. 事件觸發策略: 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 簡潔的根本。

同時這種思維帶來的優點如下:

  1. View 的獨立性和簡單性:View 自身的邏輯簡單,不需要知道太多事情,只關心上級傳來的數據,這種模式使得 View 是低耦合的,簡潔的。

  2. 高可維護性:中心化控制知道所有對資源的操作,如果發生 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. 儘量使用無狀態組件

  2. 除了控制類組件以外其他組件避免使用組件狀態

  3. 可以通過屬性計算出來的狀態不要用狀態來表示

  4. 組件的渲染避免外部依賴,按照純函數的方式寫

函數式的優點也是無副作用組件的優點:

  1. 無耦合,可移植性強: 組件可重用性高

  2. 可測試性高:組件無依賴,可以很容易的單獨測試組件

1.6.5 Flux 生態

上面已經講過 Flux 更應該算是 Facebook 提出的一種前端架構模式,而根據這種理念的 Flux 實現有很多,以下是 github star 數較高的一些實現:

  1. Facebook 官方實現

  2. Redux 目前認可度最高的實現

  3. refluxjs

  4. alt

  5. fluxxor

後面我們會在第四章中專門講解 Redux 與 React 的應用。

1.6.6 Flux 與 React 實例

@todo

user avatar lanlanjintianhenhappy 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.