React Flux实现调度链

时间:2015-04-21 20:03:31

标签: javascript reactjs flux

我试图将React与Flux架构结合使用,偶然发现了一个我无法处理的限制。 问题如下:

  1. 有一家商店,可以收听一个活动。事件有对象ID。我们需要在需要时获取对象并将其选中。
  2. 如果商店没有此ID的对象 - 它会被查询。在回调中,我们将另一个事件分派给负责选择的商店。
  3. 如果商店有对象 - 我想发送选择事件,但我不能因为调度正在进行中。
  4. 到目前为止,我想出的最佳解决方案是将内部调度包裹在setTimeout(f, 0)中,但它看起来很可怕。

    实际上问题非常普遍 - 如果每个新的调度基于先前的调度处理结果,我应该如何在没有调度嵌套的情况下组织调度链(不违反当前的Flux限制)。

    有没有人有解决此类问题的好方法?

    var selectItem(item) {
        AppDispatcher.dispatch({
            actionType: AppConstants.ITEM_SELECT,
            item: item
        });
    }
    
    // Item must be requested and selected.
    // If it's in store - select it.
    // Otherwise fetch and then select it.
    SomeStore.dispatchToken = AppDispatcher.register((action) => {
        switch(action.actionType) {
            case AppConstants.ITEM_REQUESTED:
                var item = SomeStore.getItem(action.itemId);
                if (item) {
                    // Won't work because can't dispatch in the middle of dispatch
                    selectItem(item);
                } else {
                    // Will work
                    $.getJSON(`some/${action.itemId}`, (item) => selectItem(item));
                }
        }
    };
    

3 个答案:

答案 0 :(得分:2)

你正在写自己的调度员吗? setTimeout(f, 0)是一个很好的技巧。我在最小通量here中做同样的事情。没有什么可怕的。 Javascript的concurrency model非常简单。

更强大的磁通调度程序实现应该为您处理。

答案 1 :(得分:2)

如果 ITEM_SELECT是另一个Store要处理的事件:

您正在寻找dispatcher.waitFor(array<string> ids): void,它允许您使用SomeStore.dispatchToken返回register()来强制执行商店处理活动的顺序。

我们称之为OtherStore的商店会处理ITEM_SELECT事件,而应该处理ITEM_REQUEST事件,但先调用dispatcher.waitFor( [ SomeStore.dispatchToken ] ),然后再获取任何内容结果很有意思来自SomeStore通过公共方法,例如SomeStore.getItem()

从您的示例中

,似乎SomeStore对ITEM_REQUEST的内部状态没有任何作用,因此您只需将以下行移至OtherStore有一些小的更改

// OtherStore.js
case AppConstants.ITEM_REQUESTED:
        dispatcher.waitFor( [ SomeStore.dispatchToken ] );// and don't even do this if SomeStore isn't doing anything with ITEM_REQUEST
        var item = SomeStore.getItem(action.itemId);
        if (item) {
            // Don't dispatch an event, let other stores handle this event, if necessary
            OtherStore.doSomethingWith(item);
        } else {
            // Will work
            $.getJSON(`some/${action.itemId}`, (item) => OtherStore.doSomethingWith(item));
        }

同样,如果另一家商店需要处理OtherStore.doSomethingWith(item)的结果,他们也可以处理ITEM_REQUESTED,但在继续之前请致电dispatcher.waitFor( [ OtherStore.dispatchToken ] )

答案 2 :(得分:0)

因此,在查看您的代码时,您是否正在设置&#34;已选择&#34;项目上的属性,以便在您的UI /组件中检查/选择它?如果是这样,只需制作您已经在的功能部分。

if(item) {
    item.selected = true;
    //we're done now, no need to create another Action at this point, 
    //we have changed the state of our data, now alert the components 
    //via emitChange()

    emitChange();
}

如果您想要跟踪商店中当前选择的项目,只需将ID或对象作为私有变量,并进行类似设置。

var Store = (function(){

    var _currentItem = {};
    var _currentItemID = 1;

    function selectItem(item) {

          _currentItem = item;
          _currentItemID = item.id;
          emitChange();
    }


    (function() {
         Dispatcher.register(function(action){
               case AppConstants.ITEM_REQUESTED:
                   var item = SomeStore.getItem(action.itemId);
                   if (item) {
                        selectItem(item);
                   } else {
                   $.getJSON(`some/${action.itemId}`, (item) => 
                        selectItem(item);   
                   }
         });
    })();


    return {
         getCurrentlySelectedItem: function() {
              return _currentItem;
         },
         getCurrentlySelectedItemID: function() {
              return _currentItemID;
         }
    }

})();

最终,您不必为所有事情创建动作。无论您正在操作的项目是什么,它都应该是某个域实体,管理该特定实体的状态是您的Store的工作。拥有其他内部功能通常是必需的,因此只需将selectItem(item)作为Store的内部功能,这样您就不必创建新的Action来访问它或使用它。

现在,如果您有跨存储问题,而另一个Store关心初始Store中某些数据的某些特定更改,那么waitFor(ids)函数将会进入。它会有效阻止执行直到第一个Store更新,然后另一个可以继续执行,确保其他商店的数据处于有效状态。

我希望这有意义并解决你的问题,如果没有,请告诉我,希望我能更好地归零。