React,Flux,React-Router Dispatch Error - 可能的batchUpdates解决方案?

时间:2015-02-27 07:31:32

标签: javascript reactjs reactjs-flux flux react-router

好吧,所以我遇到了reactjs,flux体系结构和react-router的问题。我有以下路线(只是一部分路线):

<Route name="prepare-seniors">
  <Route name="senior" path=":candidateId" handler={SeniorCandidate}>
    <DefaultRoute handler={SeniorProfile}/>
    <Route name="senior-recommendations" path="recommends">
      <DefaultRoute handler={SeniorRecommends}/>
      <Route name="senior-rec-new" path="new"/>
    </Route>
  </Route>
</Route>

Senior Profile视图进行API调用以加载各个人的数据。当您导航到推荐视图时,个人的ID用于进行另一次调用以加载推荐。如果我实际上首先查看配置文件页面并导航到推荐页面,它的效果很好。但如果我重新加载,我会得到:

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

我意识到这是因为在第一个API返回后调用调度,调出并开始更新组件。在完成之前,推荐页面会调用其API并尝试调度其结果。我在一个论坛上看到React.addons.batchUpdates是解决这个问题的一种方法,但我无法弄清楚如何让它发挥作用。 GitHub Batch Updates Issue和此处的另一个链接讨论类似Trying to use waitFor的内容。第一个建议通过添加以下内容来调整调度程序:

// assuming a var `flux` containing your Flux instance...
var oldDispatch = flux.dispatcher.dispatch.bind(flux.dispatcher);
flux.dispatcher.dispatch = function(action) {
  React.addons.batchedUpdates(function() {
  oldDispatch(action);
  });
};

但我无法做到这一点。也许我只是错误地实现它。

我已经阅读了Chat和TodoMVC示例。我理解在聊天示例中如何使用waitFor ...但是这些都使用相同的API,因此很明显,它将等待另一个。我的问题涉及API和调度之间的竞争条件......我不认为setTimeout是一个很好的解决方案。

我需要的是看看如何设置调度程序,使其对调度或API调用进行排队。或者更好的方法是告诉每个组件对其数据进行API调用,因此我甚至没有调度问题。

哦,所以这里是我的Dispatcher.js文件,以便您可以看到它是如何设置的:

'use strict';

var flux = require('flux'),
 Dispatcher = require('flux').Dispatcher,
 React = require('react'),
 PayloadSources = require('../constants/PayloadSources'),
 assign = require('object-assign');

//var oldDispatcher = flux.Dispatcher.dispatch.bind(AppDispatcher);
//
//flux.dispatcher.dispatch = function(action) {
//  React.addons.batchedUpdates(function() {
//    oldDispatcher(action);
//  });
//};


var AppDispatcher = assign(new Dispatcher(), {
   handleServerAction: function(action) {
     var payload = {
       source: PayloadSources.SERVER_ACTION,
       action: action
     };
     this.dispatch(payload);
   },

   handleViewAction: function(action) {
     if (!action.type) {
       throw new Error('Empty action.type: you likely mistyped the action.');
     }

     var payload = {
       source: PayloadSources.VIEW_ACTION,
       action: action
     };
     this.dispatch(payload);
    }
});
module.exports = AppDispatcher;

1 个答案:

答案 0 :(得分:0)

好的,首先我要说我现在正在学习React和Flux,我绝不是专家。不管怎么说,我打算试一试:

从你所说的,听起来你有2个异步操作触发,然后当它们返回尝试发送调度消息时,调度调用由2个独立的aync webservice调用触发两次。

我不认为批量更新会对这种情况有所帮助,因为它在很大程度上取决于时间(即,如果它已经排队重新渲染并且等待机会在第二次调用进入时执行它可能批量成功,但如果它在更新中期,你现在处于完全相同的情况。)

我认为这里的实际问题来自于触发这些动作的方式/时间(你在帖子的最后简要提到了这一点)。听起来你正在从React组件渲染调用中触发Actions(有点像延迟加载)。这几乎就是Flux试图避免的事情,因为这种模式很容易导致应用程序流中出现无限循环或奇怪的状态/模式。

正如您在描述中提到的那样,您可能需要在前面而不是单个组件中触发此加载,从我知道我建议需要在核心组件上调用React.render之前完成。如果您查看示例聊天应用,他们会在app.js中执行类似操作:

ChatExampleData.init(); // load example data into localstorage

ChatWebAPIUtils.getAllMessages();

React.render(
    <ChatApp />,
    document.getElementById('react')
);

所以我建议遵循上面的模式,在向客户端显示加载微调器的同时预先加载任何初始数据。

或者,根据您的技术堆栈,您最初可以在服务器上呈现(在ReactJS.Net上的节点示例here .Net版本),因此您在客户端启动时没有延迟(也是您如果这是一个问题,请避免使用搜索引擎索引进行所有有趣的业务(顺便说一句,我没有尝试过这些,只需阅读它们)。