我正在使用 alt作为我的一个项目的通量实现,并且在处理两个相关实体的加载存储的最佳方法方面遇到了麻烦。我正在使用 sources与 registerAsync 一起用于处理我的 async/api 调用并使用 AltContainer 将它们绑定(bind)到我的 View 的功能。
我有两个通过 conversationId 一对一相关的实体。两者都是通过 api 调用加载的:
一旦我的作业存储加载了数据,我想填充对话存储。
我使用一个源来加载作业存储:
module.exports = {
fetchJobs() {
return {
remote() {
return axios.get('api/platform/jobs');
},....
似乎是 waitFor() 方法的一项工作,但它似乎适用于一个商店的内容需要转换或与另一个商店的内容合并的情况。我需要根据另一个数据存储的内容来获取一个数据存储的内容。
一般来说,我需要:
- 调用第三方 API 并将实体列表加载到商店中。
- 当数据到达时,我需要使用上述每个属性来调用另一个 API 并将该数据加载到另一个存储中。
我的天真的解决方案是从作业存储中引用对话 Action ,并在数据到达时调度一个事件。像这样的:
var jobActions = require('../actions/Jobs');
var conversationActions = require('../actions/Conversations');
class JobStore {
constructor() {
this.bindListeners({
handlefullUpdate: actions.success
});...
}
handlefullUpdate(jobs) {
this.jobs = jobs;
conversationActions.fetch.defer(jobs);
}
}
当然,这样做违反了 store 不应该派发事件的格言,因此我必须使用 defer 在派发中间派发一个 Action 。这对我来说是有道理的,因为似乎在沿着这条道路前进时,我在我的代码中重新引入了各种副作用;失去了我应该看到的“功能管道”的美感。
此外,我的作业存储必须保存对任何依赖实体的引用,以便它可以调度适当的操作。这里我只有一个,但我可以想象很多。就实体之间的依赖关系而言,这似乎完全倒退了。
我想到了几个替代方案:
我可以在获取所有对话的源/操作中调用 api/platform/jobs 端点,只是为了获取 ID。最初的方法更有效,但这似乎更符合流动的精神,因为我失去了所有的串扰。
我也可以有单个 Action /源来获取两者,返回 {jobs:{}, conversations: in the action}
(使用 Promise 协调那里的依赖关系)并使用它填充两个商店。但这种方法对我来说似乎不必要地复杂(我觉得我不应该这样做!)。
但是我错过了另一种方式吗?奇怪的是,这样一个常见的用例会破坏通量范式的优雅和/或迫使我跳过这么多圈。
@dougajmcdonald 提出了类似的问题 here ,但可能是措辞过于笼统,没有引起任何关注:
最佳答案
这绝对是 Flux 设计中的一个缺陷,你说得对,这是一个非常常见的用例。几天来,我一直在研究这个问题(以及一些类似的问题),以便在我自己的系统中更好地实现 Flux,虽然肯定有一些选择,但大多数都有缺点。
最流行的解决方案似乎是使用容器,例如 AltContainer ,以抽象出从 api 请求数据和从商店加载到单个组件中的任务,没有 ui-logic。该容器将负责查看来自商店的信息并确定是否需要额外的操作来完成它们。例如;
static getPropsFromStores() {
var data = SomeStore.getState();
if (/*test if data is incomplete */){
SomeAction.fetchAdditionalData();
}
return data;
}
这是有道理的。我们的 Component 层中有逻辑和组件,这是 Flux 所说的所属。
直到您考虑让两个已挂载的容器请求相同信息的可能性(并因此复制任何初始化提取,即模型中的对话),并且如果您添加第三个(或第四个或第五个)问题只会变得更糟) 容器访问这些相同的商店。
Container 人群对此的 react 是“不要超过一个!”,这是一个很好的建议......如果你的要求没问题的话。
所以这是我改变的解决方案,围绕相同的概念;在整个应用程序周围(甚至在它旁边)包含一个主容器/组件。与传统容器不同,此主容器/组件不会将存储属性传递给其子级。相反,它完全负责数据的完整性和完整性。
这是一个示例实现;
class JobStore {
constructor() {
this.bindListeners({
handleJobUpdate: jobActions.success
});
},
handleJobUpdate(jobs) {
this.jobs = jobs;
}
}
class ConversationStore {
constructor() {
this.bindListeners({
handleJobUpdate: jobActions.success,
handleConversationUpdate: conversationActions.success
});
},
handleJobUpdate(jobs) {
this.conversations = {};
this.tmpFetchInfo = jobs.conversation_id;
this.isReady = false;
},
handleConversationUpdate(conversations) {
this.conversations = conversations;
this.tmpFetchInfo = '';
this.isReady = true;
}
}
class MasterDataContainer {
static getPropsFromStores() {
var jobData = JobStore.getState();
var conversationData = ConversationStore.getState();
if (!conversationData.isReady){
ConversationAction.fetchConversations(conversationData.tmpFetchInfo);
}
},
render: function(){
return <div></div>;
}
}
关于javascript - Flux/Alt 数据依赖,如何优雅地道地处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35344635/