React Flux - 在调度中调度 - 如何避免?

时间:2016-01-16 15:48:13

标签: javascript reactjs flux

我似乎遇到了一种情况,我无法避免在Flux中发送调度问题。

我已经阅读了一些关于这个问题的类似问题,但除了setTimeout黑客之外,似乎没有一个好的解决方案,我希望避免这些问题。

我实际上使用的是alt.js而不是Flux,但我认为概念是相同的。

方案

想象一下最初呈现登录表单的组件。当用户登录时,会触发XHR,该XHR最终会使用身份验证信息(例如用户名)进行响应,然后根据身份验证信息获取一些安全数据并将其呈现而不是登录表单。

我遇到的问题是当我尝试触发基于XHR响应获取数据的操作时,它仍然在发送LOGIN_RESPONSE动作,并触发可怕的

Error: Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.

实施例

我创建了this jsfiddle来证明问题。

我有一个Wrapper组件,根据用户是否在Contents中设置,可以呈现登录按钮或MyStore子组件。

  1. 首先,登录按钮呈现在Wrapper组件中。
  2. 点击该按钮会调度LOGIN操作。
  3. 延迟后,LOGIN_RESPONSE行动将被调度(通过async mechanism in alt.js)。
  4. 此操作会触发MyStore更新用户名。
  5. Wrapper组件会观察商店更改并更新其状态。
  6. 这会导致Wrapper呈现Content组件,而不是登录按钮。
  7. Content组件在mount上尝试调度FETCH_DATA操作,该操作失败,因为调度程序仍在调度LOGIN_RESPONSE。 (如果我将FETCH_DATA调度包装在setTimeout中,它可以正常运行,但感觉就像是黑客攻击了。
  8. 这种情况的变化似乎是一种常见的情况。事实上,几乎所有相关问题都有类似的情况,但没有好的或具体的答案。

    此数据流是否存在内在错误?做这样的事情的适当的Flux方式是什么?

2 个答案:

答案 0 :(得分:1)

这是在许多库中componentDidMount中调度的常见问题。解决方案是在React的批量更新中包装调度;幸运的是,Alt允许您使用batchingFunction选项执行此操作:

var alt = new Alt({
  // React.addons.batchedUpdates is deprecated:
  // batchingFunction: React.addons.batchedUpdates

  // use this instead in newer versions of React
  // see https://discuss.reactjs.org/t/any-plan-for-reactdom-unstable-batchedupdates/1978
  batchingFunction: ReactDOM.unstable_batchedUpdates
});

有关工作示例,请参阅https://jsfiddle.net/BinaryMuse/qftyfjgy/,有关不同框架中相同问题的说明,请参阅this Fluxxor issue

答案 1 :(得分:0)

我相信我们忠诚的朋友Dispatcher有权投诉。

在我得出结论之前,我会试着描述一个假设的情况。假设一个应用程序有两个存储S1和S2以及两种操作A1和A2。通常的Flux实现的正确流程应该是这样的:

  1. 组件触发操作A1(基本上是一个调度);
  2. 单一调度员将相应的有效负载分配给所有注册的商店;
  3. S1消耗有效负载并可能更新其状态;
  4. 在S1中收听更改的所有组件都会检查他们感兴趣的更改,并可能更新其内部状态(可能会触发重新呈现);
  5. S2消耗......(如第3步)
  6. 所有听到S2中的变化的组件......(如第4步)
  7. 现在所有商店都处理了动作有效负载,组件可以触发新动作(A1或A2)。
  8. 使用Flux优于传统MVC的最大优势之一是Flux为您提供可预测性的礼物。这种感觉赋予了开发人员以这样的方式使他们相信通过正确应用Flux理念,他们肯定执行的顺序总是有点类似于:

    A1> S1> S2> A2> S1> S2> ...

    这是一个非常好的交易,特别是在尝试查找错误来源时。有人可能会说,强制执行可预测的事件链可能会导致效率低下,而且他可能是正确的,特别是在处理异步呼叫时,但这是你为拥有如此大的权力所付出的代价!

    由于异步调用,事情可能会变得有点混乱。可能会发生以下事件链:

    A1> S1> A2> S2> S1> S2> ...

    也许您的应用可以很好地处理这类事件链,但这种“不可预测性”会损害Flux单向数据流的基本动机。

    我觉得社区对如何处理这种情况没有达成共识,但我会分享我的一般解决方案:“为了可预测性,请确保在最后一个完全处理之前不要触发任何新动作”。

    这样做的一种方法是在触发任何其他操作之前,下载应用程序成功重新呈现的所有必要(新)数据。在您的示例中,这可以通过首先下载LOGIN_RESPONSE和FETCH_DATA操作中涉及的数据并将其包装在单个有效负载中然后调度它来实现,因此所有组件将具有他们已经在商店中想要的数据而无需更多