FLUX中异步请求应不应该放Store中?
个人认为是应该放在
Action Creator
层的,但是时常会见到由
Store
负责API请求的flux实现。
之前我以为这是很多人受MV*的Model影响,把Store也当作了面向Server的数据代理
但是随着越来越多的见到这种用法。甚至上上周六在UPYUN举办的
线下活动
中,豆瓣的著名大牛@张克军 前辈在流程图中也将API调用交给了
Store
,如下图:
当前最流行的FLUX实现 reflux 的推荐示例 react-news 也将异步的数据操作放在了 store 中。
与此同时,Facebook的态度似乎有一些摇摆:
在在React官网的Blog中,有这么一篇介绍Flux的文章:
Flux: Actions and the Dispatcher
,其中出现的配图如下:
上图的观点很明显:
API请求应该由Action Creator负责
。
然而,在后来FLUX官网的“整理版” 同名文章 中,却去掉了上图,取而代之的是没有标注Web API的流传的最广的那张流程图。这实在是有些另人费解。
从个人的理解而言,Store代表了整个应用的当前状态。而Action则代表了对整个系统的输入,即可能改变应用状态的两类行为:
- user interaction
- server response
由于API操作可能会改变应用状态,他应该以Action的形式输入FLUX系统,而不是被Store内部消化。
当Store不包含异步逻辑时,对每一次Action输入,Store的变更都是确定的,整个应用也因此变得更加可预测,
action输入--dispatcher分发--store处理--视图渲染
也是非常完美的单向数据流动。
而如果在Store中发起API请求,每次请求至少有成功与失败两种状态,级联时可能状态更是指数上升。如果每次action产生的状态变更是无法确定的,FLUX反复强调的可预测和单向数据流要如何体现呢?
最后的总结下问题:
- FLUX中异步请求应不应该放Store中?
- 如果应该放在Store中,为什么?
@题叶 我看到你在Flux的issue中有过相关问题和讨论,最后结果似乎也是更应该放在Store之外?
Answers
我们在简聊的实践当中 Ajax 是放在 Action Creator 大致的位置的.
我倾向于这样去理解:
一个应用有 Store, 有 View,
View 跟着 Store 更新, View 上的 Action 会引起 Store 的更新.
当出现网络请求的时候, 问题不是网络请求是哪个部分, 而是
为什么需要网络请求?
更全局的看法是, 服务器上的数据库是 Store, 前端的界面是 View,
因为当前技术的限制, Store 和 View 之间有巨大的延时, 只能在前端缓存一份 Store.
这样理解, 我认为网络请求是发送 Action 到 Store 的一个过程,
对应在 Action Creator 当中做处理.
首先,不是所有对数据的请求都是要通过 Store 的。无需在 Components 之间重用的数据,则可以让 Component 自己去获取,例如:搜索时的 Auto Complete 数据查询。这种 sideway 数据未来的获取方法的讨论在
https://github.com/facebook/react/issues/3398
。
需要在 Components 之间分享的数据,则可以通过 Store 来获取,反过来通过事件通知 Component。
如果不仅想获取数据,而且也要获得调用失败的状态,那么定义专门表示错误状态的事件虽然可行,但是却会造成 Component 内的订阅代码冗余和状态混乱。
Reflux 解决这个问题的方法是,用 action 模拟 Promise。Component 可以用
someAction.triggerPromise().then/.catch
这样的方式来触发 action,获得结果或者获得错误。Store 则负责监听
someAction
,获得数据后调用
somaAction.completed(result)
触发代表成功的
someAction.completed
(这其实也是一个 action);失败了则触发
someAction.failed
。Reflux 负责将这三个 actions (实际是三个有父子关系的事件类型) 通过
triggerPromise
包装成了 Promise。
Reflux 可以包含支持 Flux 的模式(例如,Store trigger event 来通知数据变化),但是并不限定死调用模式,遇到更多需求的时候,其灵活性要强得多。因为其本质是一套 Pub/Sub 系统,但是添加了一定程度的模拟 RPC 的语法糖,以及 React 的 Mixins。