在 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 项目。它对loadTODOs
、addTODO
、deleteTODO
、editTODO
有动作。启动时,此存储不会加载所有 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 组件状态合并