How to avoid dispatching in the middle of a dispatch

Ian Walker-Sperber picture Ian Walker-Sperber · May 20, 2015 · Viewed 19.2k times · Source

Within my Flux architected React application I am retrieving data from a store, and would like to create an action to request that information if it does not exist. However I am running into an error where the dispatcher is already dispatching.

My desired code is something like:

getAll: function(options) {
  options = options || {};
  var key = JSON.stringify(options);
  var ratings = _data.ratings[key];

  if (!ratings) {
    RatingActions.fetchAll(options);
  }

  return ratings || [];
}

However intermittently fails when the dispatcher is already dispatching an action, with the message Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.. I am often making requests in response to a change in application state (eg date range). My component where I make the request, in response to a change event from the AppStore has the following:

getStateFromStores: function() {
  var dateOptions = {
    startDate: AppStore.getStartISOString(),
    endDate: AppStore.getEndISOString()
  };

  return {
    ratings: RatingStore.getAll(dateOptions),
  };
},

I am aware that event chaining is a Flux antipattern, but I am unsure what architecture is better for retrieving data when it does not yet exist. Currently I am using this terrible hack:

getAll: function(options) {
  options = options || {};
  var key = JSON.stringify(options);
  var ratings = _data.ratings[key];

  if (!ratings) {
    setTimeout(function() {
      if (!RatingActions.dispatcher.isDispatching()) {
        RatingActions.fetchAll(options);
      }
    }, 0);
  }

  return ratings || [];
},

What would be a better architecture, that avoids event chaining or the dispatcher error? Is this really event chaining? I just want to change the data based on the parameters the application has set.

Thanks!

Answer

andykenward picture andykenward · May 22, 2015

You can use Flux waitFor() function instead of a setTimeout

For example you have 2 stores registered to the same dispatcher and have one store waitFor the other store to process the action first then the one waiting can update after and dispatch the change event. See Flux docs example