提要:本文所展现示例代码,既非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; } });
【完】