Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid dispatching in the middle of a dispatch

Tags:

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!

like image 236
Ian Walker-Sperber Avatar asked May 20 '15 18:05

Ian Walker-Sperber


People also ask

What is likely to happen in Reactjs flux when a dispatch is triggered and the store gets updated?

Stores get updated because they have a callback that is registered using the dispatcher. Node's event emitter is used to update the store and broadcast the update to view. The view never directly updates the application state. It is updated because of the changes to the store.

Which method is used to dispatch actions to the Redux store?

Using the bindActionCreators method The bindActionCreators method allows us to dispatch actions from any React component that is not connected to the store as "mapDispatchToPros" in the connect function of react-redux.

How Redux dispatch works?

In Redux, dispatch needs to tell the app that the state has been updated. This happens through listeners and subscriptions. In the useReducer hook, React recognizes that the state was updated and re-renders the component. The updated state is then returned to the component from where the useReducer hook was called.


2 Answers

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

like image 56
andykenward Avatar answered Sep 20 '22 15:09

andykenward


My particular error was occurring because my stores emitted their change event during the action dispatch, while it was still cycling through the listeners. This meant any listeners (ie components) that then triggered an action due to a data change in the store would interrupt the dispatch. I fixed it by emitting the change event after the dispatch had completed.

So this:

this.emit(CHANGE_EVENT);

Became

var self = this;

setTimeout(function() { // Run after dispatcher has finished
  self.emit(CHANGE_EVENT);
}, 0);

Still a little hacky (will probably rewrite so doesn't require a setTimeout). Open to solutions that address the architectural problem, rather than this implementation detail.

like image 35
Ian Walker-Sperber Avatar answered Sep 18 '22 15:09

Ian Walker-Sperber