Flux: waitFor specific event
Asked Answered
N

1

3

I'm trying to understand how to resolve dependencies among stores. The problem is I have a comprehensive data tree, which need to be fetched from server with the chain of request that depends one on another.

PROBLEM: waitFor seams not to be supposed for async requests. Suppose next event chain:

  1. NEED_A (look at StoreA)
  2. NEED_B (look at StoreB) Here StoreB do AppDispatcher.waitFor([StoreA.dispatchToken]). But actually we want to wait for GET_A
  3. SOME_OTHER_ACTION (look at StoreA)

The third step breaks waitFor from the second step since StoreA.dispatchToken was called for SOME_OTHER_ACTION.

Question: What is a true way to wait for some specific action (GET_A)?

Let's take a look at the code (please pay attention to three PROBLEM comments):

StoreA

var a = [];

var StoreA = assign({}, EventEmitter.prototype, {

   getAProps: () => copyOfAProps(a);

   asyncGetA: () => ... //Async request returns Promise
});

StoreA.dispatchToken = AppDispatcher.register((action) => {

  switch(action.type) {
     NEED_A:
       StoreA.asyncGetA().then((data) => {             
         ActionCreator.getA(data); //Dispatches GET_A event
       });
       break;
     GET_A: 
       a = action.data;
       StoreA.emitChange();
     SOME_OTHER_ACTION: 
       //do whatever
  }

});

StoreB

var b = [];

var StoreB = assign({}, EventEmitter.prototype, {

   // PROBLEM: this request depends on data fetched from StoreA.asyncGetA
   asyncGetB: (A) => ...
});

StoreB.dispatchToken = AppDispatcher.register((action) => {

  switch(action.type) {
    //PROBLEM: NEED_B may happen before GET_A
    NEED_B:
      //PROBLEM: As I understand waitFor doesn't work here
      AppDispatcher.waitFor([StoreA.dispatchToken]);
      StoreB.asyncGetB(StoreA.getAProps()).then((data) => {
        ActionCreator.getB(data);
      });
    GET_B:
      b = action.data;
      StoreB.emitChange();
  }
});
Nuncle answered 12/9, 2015 at 10:6 Comment(2)
I use a chain of actions rather than a wait for.Candelariacandelario
@JanakaStevens what do you mean? Example pleaseeeee!)Nuncle
C
3

Here is an example from https://github.com/calitek/ReactPatterns React.13/ReFluxWebSocket. App.js triggers an action which the Api.Store acts on with ws.api.js. Then ws.api.js triggers another action which Api.Store reacts to. That is an example of a chain of actions.

This is Api.Store.js

    import Reflux from 'reflux';

    import Actions from './Actions';
    import ApiFct from './../utils/ws.api.js';

    function _apiInit() { ApiFct.init(); }
    function _apiInitDone() { ApiFct.getData(); }
    function _apiSetData(data) { ApiFct.setData(data); }

    var ApiStoreObject = {
        listenables: Actions,
        apiInit: _apiInit,
        apiInitDone: _apiInitDone,
        apiSetData: _apiSetData
    }
    const ApiStore = Reflux.createStore(ApiStoreObject);
    export default ApiStore;

This is ws.api.js

    import Actions from '../flux/Actions';

    module.exports = {
        socket: {},
        init: function() {
            this.socket = new Primus();
            this.socket.on('server:GotData', this.gotData);
            Actions.apiInitDone();
        },
        getData: function() { this.socket.send('client:GetData', {}); },
        gotData: function(data) { Actions.gotData(data); Actions.gotData2(data); },
        setData: function(data) { this.socket.send('client:SetData', data); },
    };

This is Actions.js

    import Reflux from 'reflux';

    var apiActions = [
        'apiInit',
        'apiInitDone',
        'apiSetData'
    ]

    var wsActions = [
        'gotData',
        'gotData2'
    ]

    var actionArray = wsActions.concat(apiActions);
    module.exports = Reflux.createActions(actionArray);

This is app.js

    'use strict';

    import React  from 'react';

    import AppCtrl from './components/app.ctrl.js';
    import Actions from './flux/Actions';
    import ApiStore from './flux/Api.Store';

    window.React = React;

    Actions.apiInit();

    React.render( <AppCtrl />, document.getElementById('react') );
Candelariacandelario answered 12/9, 2015 at 18:27 Comment(10)
this example is about chaining synchronous actions. Yeah, there is one async request to server, but only one. My question is about chaining to asynchronous requests that depends btw one another.Nuncle
grammar error, I ment: *"chaining two asynchronous requests"Nuncle
I believe the pattern applies whether the actions are synchronous or asynchronous. The example just happens to be synchronous. I use the same pattern for asynchronous actions also.Candelariacandelario
may you bring an example with two async callbacks, where one depends on another and may happen before it?Nuncle
The idea of a chain is to avoid multiple concurrent callbacks. If one call to the server triggers two actions then you would use a chain on the server to avoid that. Otherwise you are just having to code a wait-for. Parallel programming is very complex. You want to avoid that.Candelariacandelario
the problem is that I don't know which event will happen first (due nature of async callbacks). So I don't know in which order to chain them.Nuncle
You should be able to control the order on the server. You use async in series rather than parallel.Candelariacandelario
the last question - what should happen when user request B data, which depends on A data? At the moment user request B, A data were requested but haven't been fetched yetNuncle
The simple way is not to let them request B data until A data arrives.Candelariacandelario
The complex way is to first send the get-B to A and A has state on whether A is in or not. If not set getB-state in A and when A gets in trigger getB if requested. Otherwise just pass the getB on.Candelariacandelario

© 2022 - 2024 — McMap. All rights reserved.