MV*
説Flux之前,先説説熟知的MV*模式。 MV*一般指MVC/MVVM.
MVC如我們熟知:
- M = Model,負責數據的保存,檢驗,獲取等。
- V = View,數據的展示,DOM元素。
- C = Controller,與傳統的controller定義不同,前端中的controller的定義比較模糊。但一般作為Model和View之間的協調。
而MVVM,就是在MVC的基礎上,用VM(ViewModel)替代Controller。
也就是數據綁定,界面與VM的數據狀態可以相互影響。
説到這裏,其實不難想象,數據可以多方影響,來源不明且多樣。混亂的數據流嚮導致項目後期,開發維護的難度加大。Model的構建數量過多,會影響View的構建結構與渲染優化。
Flux
Flux 的命名來自於拉丁語Flow。是一套基於dispatcher的前端應用架構模式。
\>核心思想是數據和邏輯永遠單向流動。
對比MV* 結構,Flux模式有着數據來源單一,數據變動可溯源的優點。讓邏輯架構更加謹慎清晰。
這裏和React組件間的單向流動不同。React的單向數據流動是一般指基於Props的組件間通信設計。而Flux的單向數據流,則是基於整個架構上的。
1. Dispatcher
一個全局唯一的數據流處理中心。有3個主要API:
- dispatch(object payload) : void
用於分發action。執行已註冊的監聽。
* **register(function callback) : string**
註冊監聽用於響應dispatch。 返回一個token可供waitFor()使用。
* **waitFor(array ids) : void**
當在回調中遇到waitFor()時,該回調暫停執行。在waitFor()完成執行並回調之後,再繼續執行原始回調。此方法可以用於等待並執行其他store操作。
*action是一個對象類型,在FSA規範中對其字段進行了列舉:type,error,payload,meta。其中type(或者name)為必須,是store根據action修改數據的依據。
在Facebook的Flux實例源碼中,在Dispatcher類裏定義了一個\_callbacks數組,保存了在register方法中註冊的監聽器。並在dispatch方法中遍歷執行,且把action作為參數傳入監聽函數。
2. Store
一般有以下幾個功能:
- 保存狀態數據(state)。
- 暴露一個Getter用於獲取狀態
- 定義修改數據的邏輯。
- 調用Dispatcher.register方法將自己註冊為一個監聽器。
- 定義一個更新監聽方法
當調用dispatch分發action,store在register方法中註冊的監聽就會被調用,同時得到傳入action。
store將根據action攜帶的type判斷是否響應操作。如響應,調用內部的數據修改邏輯。並在執行完畢後觸發更新事件。
3. Controller-View/View
Controller-View一般作為最頂層的View,負責Store和View之間的數據傳遞。
- **進行store與View的綁定,定義數據更新及傳遞方式。**這裏説的View一般是React,當然也可以是其他框架。
- **監聽Store發出的更新事件。**當Store更新後,Controller-View會重新獲取store中的數據,並觸發界面重繪。
class CounterContainer extends Component {
static getStores() {
return [CounterStore];
}
static calculateState(prevState) {
return {
counter: CounterStore.getState(),
};
}
render() {
return ;
}
}
const container = Container.create(CounterContainer);
上面是Flux官方文檔中將一個React Class創建為Controller-View的簡單調用實例。class向外暴露getStores、calculateState兩個方法:
- getStores用於綁定Class關聯的Store。
- calculateState用於獲取Store中的數據轉化為自身的State,並作為props傳給子組件。
Container.create方法中,會獲取綁定的Store中dispatchToken,然後根據dispatchToken利用waitFor方法等待Store完成數據更新邏輯,然後執行更新回調。
當Store觸發更新後,Container會調用setState方法更新State,同時觸發畫面渲染更新。
當然關聯store、更新回調等可以有多種實現方法,以上只是其中一種思路。
View就是界面表現了,View可以通過props獲得Container傳入的數據。
如果View需要修改數據,必須使用dispatcher分發action的方式進行修改。
這也是單向數據流的重要特徵,view不能直接修改數據。
説起Flux,很多第一句就是單向數據流。但其實數據中心化控制,也是特點之一。
所有的更改,必須通過action發出,dispatcher分配。store中心化控制了數據,令數據管理和問題追查變得清晰容易。
action的管理,令架構不用關心辨別數據更新的觸發方式,所有觸發方式都抽象成了action。Flux架構並非React獨有,也能作為其他組件框架的狀態管理方案。
前面説到Flux對於MV*架構的優點,當然Flux本身也有的坑。雖然後面提出的Redux,則對Flux中state與更新邏輯沒有分離抽象,沒有對URL路由進行管理等問題進行改進。但Flux只是一種設計約定,各人對其都有自己的觀點和想法。與其他架構相比其實沒有絕對的優勢劣勢,只是提供解決方案的一種。