应该通量存储或行动(或两者)接触外部服务?

如果商店保持自己的状态,并有能力调用networking和数据存储服务…在这种情况下,这些行为只是愚蠢的消息传递者,

-要么-

如果商店是来自动作的不可变数据的愚蠢收件人(并且动作是在外部源之间获取/发送数据的动作),在这种情况下的存储将作为视图模型,并且能够聚集/过滤它们数据在它们自己的状态基础上设置它们由动作提供的不变数据。

在我看来,它应该是一个或另一个(而不是两者的组合)。 如果是这样,为什么比另一个更受欢迎/推荐?

我已经看到了两种方式实现的stream量模式,并且在我自己完成(最初采用前一种方法)之后,我认为商店应该是来自操作的数据的愚蠢收件人,并且写入的asynchronous处理应该存在于行动的创造者。 ( asynchronous读取可以被不同地处理 。)根据我的经验,这有几个好处,按重要性排列:

  1. 您的商店变得完全同步。 这使得您的商店逻辑更加容易遵循,而且非常容易testing,只需实例化某个给定状态的商店,发送一个动作,然后检查状态是否按预期更改。 此外,stream量的核心概念之一就是防止级联调度,同时防止多次调度; 当你的商店做asynchronous处理时,这是非常困难的。

  2. 所有的行动都是由行动创造者发起的。 如果您在商店中处理asynchronous操作,并且希望保持商店的操作处理程序同步(并且您应该为了获得通量单一分派保证),则您的商店将需要触发额外的SUCCESS和FAIL操作以响应asynchronous处理。 将这些派遣放在动作创作者中,而是帮助分离动作创作者和商店的工作; 此外,您不必深入挖掘您的商店逻辑,以确定行动是从哪里发出的。 在这种情况下,一个典型的asynchronous操作可能看起来像这样(根据您使用的stream量的风格改变dispatch调用的语法):

     someActionCreator: function(userId) { // Dispatch an action now so that stores that want // to optimistically update their state can do so. dispatch("SOME_ACTION", {userId: userId}); // This example uses promises, but you can use Node-style // callbacks or whatever you want for error handling. SomeDataAccessLayer.doSomething(userId) .then(function(newData) { // Stores that optimistically updated may not do anything // with a "SUCCESS" action, but you might eg stop showing // a loading indicator, etc. dispatch("SOME_ACTION_SUCCESS", {userId: userId, newData: newData}); }, function(error) { // Stores can roll back by watching for the error case. dispatch("SOME_ACTION_FAIL", {userId: userId, error: error}); }); } 

    逻辑,否则可能被复制到各种行动应提取到一个单独的模块; 在这个例子中,该模块是SomeDataAccessLayer ,它处理实际的Ajax请求。

  3. 你需要更less的行动创造者。 这不是一个大问题,但很高兴有。 如#2所述,如果你的商店有同步动作调度处理(他们应该),你将需要额外的动作来处理asynchronous操作的结果。 在动作创build者中执行调度意味着单个动作创build者可以通过处理asynchronous数据访问本身的结果来调度所有三种动作types。

我把这个问题推给了Facebook上的开发人员,我从Bill Fisher得到的答案是:

在响应用户与UI的交互时,我会在动作创build器方法中进行asynchronous调用。

但是,当你有一个自动收报机或其他非人力驱动程序,从商店打来的电话效果更好。

重要的是在错误/成功callback中创build一个动作,所以数据总是以动作开始

商店应该尽一切努力,包括提取数据,并向组件发送信息,指出商店的数据已经更新。 为什么? 因为行动可以是轻量级的,一次性的和可replace的,而不会影响重要的行为。 所有重要的行为和function都在商店中发生。 这也防止了行为的重复,否则会被复制成两个非常相似但不同的行为。 商店是你(处理)真相的唯一来源。

在每个Flux实现中,我已经看到Actions基本上是事件string变成对象,就像传统上你会有一个名为“anchor:clicked”的事件,但是在Flux中它将被定义为AnchorActions.Clicked。 他们甚至是“愚蠢的”,大多数实现具有单独的Dispatcher对象,实际上将事件分派到正在监听的商店。

就我个人而言,我喜欢Reflux的Flux实现,没有单独的Dispatcher对象和Action对象进行自我调度。


编辑:Facebook的Flux实际上提取“行动创造者”,所以他们使用智能行动。 他们也使用商店准备有效载荷:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/actions/ChatMessageActionCreators.js#L27 (第27和28行)

完成时的callback将会触发一个新的动作,这次获取的数据是有效载荷:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/utils/ChatWebAPIUtils.js#L51

所以我想这是更好的解决scheme。

我会提供一个赞成“愚蠢的”行动的论点。

通过将收集视图数据的责任置于您的操作中,您可以将操作与视图的数据要求相结合。

相比之下,声明性地描述用户意图或应用程序中某些状态转换的generics操作允许任何响应该操作的存储将意图转换为专门针对订阅的视图而定制的状态。

这适用于更多,但更小,更专业的商店。 我争辩这种风格,因为

  • 这使您在视图如何使用Store数据方面有更大的灵活性
  • 专门针对消费者的视图的“智能”商店对于复杂的应用程序而言将会更小,更less耦合,而不是“智能”

商店的目的是为视图提供数据。 “行动”这个名字暗示我的目的是描述我的应用程序的变化。

假设您必须将一个小部件添加到现有的Dashboard视图中,该视图显示了后端团队刚推出的一些奇妙的新聚合数据。

使用“智能”操作,您可能需要更改“刷新仪表板”操作,以使用新的API。 但是,抽象意义上的“刷新仪表板”并没有改变。 你的观点的数据要求是什么改变了。

使用“哑”操作,您可以为新小部件添加一个新的存储区,并设置它,以便当它接收到“刷新仪表板”操作types时,它会发送一个新数据请求,并将其公开一旦准备就绪,新的小部件 我认为,当视图层需要更多或不同的数据时,我改变的东西就是数据的来源:商店。

gaeron的flux-react-router-demo有一个很好的“正确”方法的实用变体。

ActionCreator从外部API服务生成一个承诺,然后将承诺和三个操作常量传递给代理/扩展Dispatcher中的dispatchAsync函数。 dispatchAsync将总是分派第一个动作,例如“GET_EXTERNAL_DATA”,一旦promise返回,它将分派“GET_EXTERNAL_DATA_SUCCESS”或“GET_EXTERNAL_DATA_ERROR”。

如果你希望有一天有一个开发环境可以与Bret Victor着名的video发明原理相比 ,你应该使用哑数据库,这只是数据结构中动作/事件的投影,没有任何副作用。 如果你的商店实际上是同样的全球不变的数据结构的成员,这也将有所帮助,就像在Redux中一样 。

更多的解释在这里: https : //stackoverflow.com/a/31388262/82609