在 React/Flux 中管理存储数据依赖

Posted

技术标签:

【中文标题】在 React/Flux 中管理存储数据依赖【英文标题】:Managing store data dependency in React/Flux 【发布时间】:2014-09-03 14:48:16 【问题描述】:

我有一个使用 Facebook 的 Flux 架构开发的网络应用程序。该页面有两个视图:一个显示 TODO 项目列表。第二个视图显示一组随机的 TODO 项。

显然有两个问题需要由商店管理。第一个是可用 TODO 的列表。第二个是随机选择的TODO项目列表。

因此,我有一个TODOStore,他只关心管理可用的 TODO 项目。它对loadTODOsaddTODOdeleteTODOeditTODO 有动作。启动时,此存储不会加载所有 TODO 项。我希望它仅在必要时从数据库中检索 TODO 项列表。

第二家商店是RandomTODOListStore。它的职责是管理随机选择的 TODO 项。在我看来,RandomTODOListStore 应该使用TODOStore.getTODOItems() 通过TODOStore 访问 TODO 项。

function RandomTODOListStore() 
   var $randomTODOs = [];

   dispatcher.register(function(payload) 
        var action = payload.action;

        switch (action.actionType) 
            case Constants.LOAD_RANDOM_TODO:
                loadRandomTODO();
                break;
        
    );

    function loadRandomTODO() 
        $randomTODOs = selectRandom(TODOStore.getTODOList());
        emit("change");
    

问题在于,如前所述,TODOStore 在启动时不会加载 TODO 项。

问题是:RandomTODOListStore如何保证TODOStore已经检索到TODO项目?”

【问题讨论】:

【参考方案1】:

提议的 Flux 实现使用waitFor 方法来同步存储。我创建了Reflux,让商店能够听取其他商店的意见,从而更轻松地处理这个问题。该功能的效果是,它将保证链中的前一个商店已经处理了它的数据。

界面有点不同,因为 Reflux 不依赖字符串常量来识别动作,所以这里是一个例子。

var TodoActions = Reflux.createActions(['load']);

var todoStore = Reflux.createStore(
    init: function() 
        // Listen to the load action
        this.listenTo(TodoActions.load, this.loadActions);
    ,
    loadActions: functions() 
        var loadedActions = [];
        // load your actions into loadedActions
        // and do then the following inside the ajax 
        // callback when it is done:
        this.trigger(loadedActions);
    
);

var randomTodoStore = Reflux.createStore(
    init: function() 
        // You may listen to stores as well
        this.listenTo(todoStore, onLoadedActions);
    ,
    onLoadedActions: function(loadedActions) 
        // loaded actions will be passed in from the
        // dotoStores change event trigger

        // you may do your select random from loaded 
        // actions list   
    
);

// Invoke the action
TodoActions.load();

希望这是有道理的。

【讨论】:

【参考方案2】:

我认为这就是为什么 Flux 架构提到需要使用 waitFor 方法同步存储的原因提到 here

如果您想同步您的商店,您的 RandomTODOListStore 应该如下所示:

case Constants.LOAD_RANDOM_TODO:
  Dispatcher.waitFor([TodoStore.dispatcherIndex],this.loadRandomTODO);
  break; 

然后在您的 TodoStore 上,您可以对 Constants.LOAD_RANDOM_TODO 做出反应并加载尚未加载的待办事项列表。

但是我认为这过于复杂,您可能不应该为随机 todos 创建另一个存储,因为这个存储(我猜)总是委托给真正的 todo 存储。只需改用TodoStore.getRandom()

编辑

是的 TodoStore 不需要知道它是如何使用的。因此,当您想获得一个随机的待办事项时,您可能可以使用您使用的相同事件,例如Constants.LOAD_TODOS,然后使用TodoStore.getTodos()[randomIndex]从该商店获得一个随机待办事项

如果两个组件同时触发事件,您可以忽略第二个事件

另一种解决方案是让RandomTODOListStore 对加载的事件做出反应并选择主商店的一些待办事项将它们放入RandomTODOListStore:

case Constants.TODOS_LOADED:
  this.randomTodos = randomSubset(TodoStore.getTodos,subsetSize);
  break; 

您可以从Async exemple from Fluxxor 中激发自己的灵感:对于异步数据,不仅会触发一个事件,还会触发 2 个事件(命令 + 成功/失败)

【讨论】:

是的,我确实考虑过。问题在于 TODOStore 不应该关心其他人如何使用它。它不应该对 RandomTODOListStore 动作做出反应。想象一下,每当我有其他需要 TODO 项的东西时,TODOStore 会很快变得臃肿。【参考方案3】:

您的 RandomTODOListStore 需要等待 TODOStore。您可以使用这个库(我的)https://github.com/kjda/ReactFlux

轻松实现这一点
var ReactFlux = require('react-flux');

var TODOConstants = ReactFlux.createConstants(['LOAD'], 'TODO');

var TODOActions = ReactFlux.createActions(
    load: [TODOConstants.TODO_LOAD, function()
      //load your todos here
      return  todos: [title: 'do this', title: 'do that']
    ]
);

var TODOStore = ReactFlux.createStore(
    getTodos: function()
       return this.getState().todos;
    
, [
   [TODOConstants.TODO_LOAD_SUCCESS, function(payload)
      this.setState(
          todos: payload.todos
      );
   ]
]);

var RandomTODOListStore = ReactFlux.createStore(
    selectRandomFromList: function(todos)
      //..... select some here
    
, [

   /**
    * This waits for TODOStore to process the message first
    */
   [TODOConstants.TODO_LOAD_SUCCESS, [TODOStore], function(payload)
        this.selectRandomFromList(payload.todos);
   ]

]);

现在,当您的应用启动时,您只需调用操作

TODOActions.load();

【讨论】:

以上是关于在 React/Flux 中管理存储数据依赖的主要内容,如果未能解决你的问题,请参考以下文章

React/Flux - 监控 api 和更新存储新数据的最佳方式?

将 Flux 存储中的 Immutable.js 映射与内部 React 组件状态合并

在 React+Flux 中异步处理不影响视图的数据

React/Flux 存储不会改变它的状态

在 ES6 中使用 Jest 测试 React Flux Store

React + Flux:如何重置商店?