reflux / refluxjs

A simple library for uni-directional dataflow application architecture with React extensions inspired by Flux
BSD 3-Clause "New" or "Revised" License
5.36k stars 330 forks source link

How to wait until multiple actions, triggered with one dispatcher, complete? #474

Open ghost opened 8 years ago

ghost commented 8 years ago

For example, i have one action Clear and many stores which are listening to it, how to do something only after Clear action is completed in all stores?

devinivy commented 8 years ago

You may be interested in reflux ability to "join" actions: https://github.com/reflux/refluxjs#joining-parallel-listeners-with-composed-listenables

ghost commented 8 years ago

Can you give me some examples? It`s stupid question, but how to use reflux api? I mean how to call its methods.

devinivy commented 8 years ago

It's not stupid at all! In this case you would create a store and create some actions. Stores have the ability to listen to actions. The "join" functionality is a feature of a store that allows it to listen to a composite of several actions. Here's a more complete example,

var Reflux = require('reflux');

var Actions = Reflux.createActions([
  'disarmBomb',
  'saveHostage',
  'recoverData'
]);

var gainHeroBadgeStore = Reflux.createStore({
  init: function() {
    this.joinTrailing(Actions.disarmBomb, Actions.saveHostage, Actions.recoverData, this.onBadge);
  },
  onBadge: function(data) {

    // Let store react to the events above having all taken place

    // Then notify everyone the store has updated
    // this.trigger();
  }
});

Actions.disarmBomb('warehouse');
Actions.recoverData('seedyletter');
Actions.disarmBomb('docks');
Actions.saveHostage('offices', 3);
ghost commented 8 years ago

i think, i have different case, i have many stores listening one action, but not one store listening many actions, thanks for the example, it`s very useful

devinivy commented 8 years ago

If you have many stores listening to one action then it might look more like this,

var Reflux = require('reflux');

var Actions = Reflux.createActions(['disarmBomb']);

var FirstStore = Reflux.createStore({
  init: function() {
    this.listenTo(Actions.disarmBomb, this.onDisarm);
  },
  onDisarm: function(data) {

    // Let store react to the event having taken place

    // Then notify everyone the store has updated
    // this.trigger();
  }
});

var SecondStore = Reflux.createStore({
  init: function() {
    this.listenTo(Actions.disarmBomb, this.onDisarm);
  },
  onDisarm: function(data) {

    // Let store react to the event having taken place

    // Then notify everyone the store has updated
    // this.trigger();
  }
});

Actions.disarmBomb('warehouse');
devinivy commented 8 years ago

Oh, I understand. You should also be able to listen to all stores. So if you have a store that wants to wait for some stores to trigger() after an action it might look like,

this.joinTrailing(Actions.disarmBomb, FirstStore, SecondStore, callback);
ghost commented 8 years ago

Wow, it`s exactly what i meant, thanks, I think that those examples need to be included to documentation

Updated:

callback will be called for each action emmission, but i need it to be called only for the last emmission

i.e

var Actions = Reflux.createActions([
  'action'
]);

var Store1 = Reflux.createStore({
  listenables: [Actions],

  action: function () {
  //do something
  }
});

var Store2 = Reflux.createStore({
  listenables: [Actions],

  action: function () {
  //do something
  }
});

var Store3 = Reflux.createStore({
  init: function () {
    this.joinConcat(Actions.action, Store1, Store2, this.action);
  },

  action: function () {
    console.log('tadah');
  }
});

will cause 2 console logs

ghost commented 8 years ago

Is there anybody? Im still looking for answer)) I have found workaround by using callbacks in actions, it works, but its bad and unreadable

devinivy commented 8 years ago

I don't quite understand. Can you expand your example to include the action call and store updates? Is the join working as described here?

ghost commented 8 years ago

The example is below, i need method action from Store3 to be invoked only when all dispatched actions completed, instead of being called for each action when it`s completed. And yes, join works fine but not for my case.

devinivy commented 8 years ago

What are the actions included in "all dispatched actions"?

ghost commented 8 years ago

An action from each store Store1 and Store2

semikolon commented 8 years ago

joinTrailing should do the job, as explained above

BryanGrezeszak commented 7 years ago

If I understand the issue correctly, would a simple postEmit function (as in a counterpart to the preEmit that already exists) solve this?

So something like:

var Actions = Reflux.createActions(['doAction']);

Actions.doAction.postEmit = function()
{
    console.log('the action is done emitting');
}

Obviously it's kinda impossible to figure out whether whatever you're doing inside your stores on that action is complete (because for all we know you could be starting a 24 hour setTimeout inside there or something, and that's not Reflux's business to know or care) but it would be able to tell you when the action had finished emitting to all of your stores (i.e. all the onDoAction or whatever functions within them will have been called).

ghost commented 7 years ago

Sorry for not responding so long, i ended up using redux instead of reflux, at least it support promises all i needed is something similar to Promise.all([Action1(), Action2(), Action3(), ...])

BryanGrezeszak commented 7 years ago

My bad. I thought you said that you had a situation where you had 1 action and many stores listening and needed to know when that action was emitted to all stores.

Either way, returning promises on an action call sounds good. I'm gonna look into adding that.

BryanGrezeszak commented 7 years ago

Reopened. The fact that the original asker moved on does not resolve the issue.