提要:本文所展現示例代碼,既非JQuery代碼,也是不React代碼,爲介於二者間的,方便行文僞代碼。代碼意思經過上下文便可理解。javascript
Facebook的Jing Chen同窗在2014年的F8上演示了她的FLUX
架構。前端
FLUX
的工做流以下:java
可是,若是隻是上述那個簡單的話,就實在沒什麼好說的了。舉個例子,若是我有一個TodoList,在點擊添加item的時候,須要把內容發送到服務器,根據服務器返回的結果,顯示成功或失敗的結果,那麼採用FLUX則是這麼寫的:ajax
javascript
dispatcher.register(function(payload){ switch(payload.actionType) { case "ADD_ITEM": ajax("/add/item", payload.data, function success(res){ dispatcher.dispatch("ADD_SUCCESS", payload.data); }, function failure(){ dispatcher.dispatch("ADD_FAIL", payload.data); }); break; case "ADD_SUCESS": // do something break; case "ADD_FAIL" // do something break; } }); // 在組件中發出 $("#add").click(function(){ dispatcher.dispatch({ actionType: "ADD_ITEM", data: $("input").val() }); });
上述代碼是有問題的,由於在Store中發出異步請求,而後在回調中又發出ACTION,這種狀況屬於Nested Update
,致使的問題有:服務器
固然,最最終致使的結果就是:難以維護。架構
所以,在FLUX中,首要的一個原則就是:異步
STORE代碼同步化函數
上面的代碼能夠改爲:測試
dispatcher.register(function(payload){ switch(payload.actionType) { case "ADD_ITEM": // 顯示小菊花,表示"正在加載" break; case "ADD_SUCESS": // 顯示加載成功 break; case "ADD_FAIL" // 顯示加載失敗 break; } }); $("#add").click(function(){ var msg = $("input").val(); dispatcher.dispatch({ actionType:"ADD_ITEM", data: msg }); ajax('add/item', msg, function success(res) { dispatcher.dispatch({ actionType:"ADD_SUCESS", data: res }); }, fail(res){ dispatcher.dispatch({ actionType:"ADD_FAIL" data: res }); }); });
這樣在store中的三個case裏的操做都是同步的了,即任何action,咱們都很清楚其觸發了以後,具體發生了什麼事情。this
注:不要被上面代碼中的註釋迷惑,Store並不該該去操做DOM,上面的註釋只是說明其以後發生了什麼。
上面的例子中,咱們將ajax請求放在組件中,成功時觸發一個action,失敗時又觸發另外一個,使得程序行爲是徹底可預測的。但若是這個ajax請求的數據很是複雜呢,組件內部就沒法發出請求了,由於它沒有收集這些數據的能力。
舉個例子,在一個購物車頁面內,勾選增長/刪除某個商品,會:
上面的關鍵步驟發送ajax
到後臺,咱們並不能在商品數量組件中發送,由於單個組件沒法收集整個商品列表的信息,若是它能夠收集的話,你的程序就很差維護了,由於你的組件強依賴於外部信息。
這種狀況彷佛又繞回了篇首的寫法,由於store中有相應的信息,那麼就在store收集數據,發出ajax呀。(又有同窗提議說,讓組件從Store中取數據,不就能收集到所需數據了嗎?)。 注意,FLUX另外一原則是:
不要讓你的組件強依賴於Store,你組件的數據應該來自於父組件,而不是Store。強依賴於Store的後果是:
* 你的組件難以複用
* 你的組件難以測試
在此例中,我能想到的解法應該是,經過父組件傳入回調給子組件處理:
// 購物車中 <Cart> <Quantity onChange={function(quantity){ // 1. 收集全部商品信息 var info = getAllDealsInfo(); // 2. 當前商品數量+1 info[this.id]++; // 3. 發出請求 ajax('/checkTotal', info, function(total) { // 當服務器返回時, dispatcher.disptach({ actionType: 'CHANGE_TOTAL', total: total }); }); }} /> </Cart> //數量組件中 input.on('change', function(){ // 發出action,可能某個角落有store監聽這個action // 用以統計當前全部商品的數量 dispatch.dispatch({ actionType: "CHANGE_QUANTITY", id: this.id, quantity: this.value }); // 調用父組件傳來的onChange函數 this.props.onChange(); });
如此,一可保持Store中代碼的同步化,二可保持組件中對外部世界的無知。
FLUX另外最重要的特色就是,很是容易擴展。舉例而言,在上面購物車例子中,若是我要增長一個區塊顯示每樣商品的數量,我不須要修改原有的代碼,只須要新增長一個store便可。
dispatcher.register(function(payload) { switch(payload.actionType){ case "CHANGE_QUANTITY": // 1. 收集全部商品的數量 // 2. update對應的model,更新view break; } });
【完】