Flux / Alt数据依赖,如何优雅和惯用处理 [英] Flux/Alt data dependency, how to handle elegantly and idiomatically

查看:83
本文介绍了Flux / Alt数据依赖,如何优雅和惯用处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用



一旦我的作业商店加载了我想要填充对话商店的数据。



我使用来源加载作业商店:

  module.exports = {
fetchJobs(){
return {
remote(){
return axios.get ( 'API /平台/作业');

},....

好像是<的工作strong> waitFor()方法,但似乎在一个商店的内容需要转换或与另一个商店的内容合并时使用。我需要根据另一个数据存储的内容获取一个数据存储的内容。



一般来说,我需要:




  • 调用第三方API并将实体列表加载到商店中。

  • 当数据到达时,我需要使用上述每个属性调用另一个API并将该数据加载到另一个商店。



我天真的解决方案是引用作业存储中的对话操作,并在数据到达时发送事件。这样的事情:

  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);
}
}

当然,这样做,违反了存储的格言不应该派遣事件,所以我必须使用延迟在派遣中间派遣一个行动。这对我来说很有意义,因为它似乎沿着这条路走下去,我在我的代码中重新引入了各种各样的副作用;失去了我应该看到的功能性管道之美。



此外,我的求职店必须持有对任何依赖实体的引用,以便它可以发送适当的行动。在这里,我只有一个,但我可以想象很多。就实体之间的依赖关系而言,这似乎完全倒退。



我想到了几种选择:



我可以在源/操作中调用 api / platform / jobs 端点来获取所有对话,只是为了获取id。最初的方法更有效率,但这似乎更为真实,因为我失去了所有的交谈。



我也可以有单一的动作/来源获取两者,返回 {jobs:{},对话:在操作中} (使用promises编排依赖关系)并使用此填充两个商店。但这种方法对我来说似乎不必要地复杂化(我觉得我不应该这样做!)。



但是我错过了另一种方式吗?奇怪的是,这样一个常见的用例会破坏磁通天堂的优雅和/或迫使我跳过如此多的箍。



@dougajmcdonald提出了类似的问题这里,但也许它的措词过于普遍,并没有得到任何牵引力:

解决方案

我一直在关注@ gravityplanx的回答,但不确定它改善了多少情况。



重申并放大:我真的非常喜欢从一个来源加载我的商店的alt模式。每个需要商店的组件看起来都是这样的:

  export default class extends React.Component {
componentDidMount(){
CurrentUser.fetch();
Jobs.fetch();
};
render(){
return(
< AltContainer stores = {{user:CurrentUser,jobs:Jobs}}>
< Body />
< / AltContainer>)
}

}

意图一目了然是可以理解的。我对问题进行了彻底的分离,使我可以更轻松地测试我的操作/商店和来源。



但是我的常见用例中的美丽模式已经崩溃了问题,我最终不得不在我的行动和商店中创建一些相当复杂的管道,以协调对话的ajax调用。另一个答案似乎只是将这种复杂性转移到别处。我希望它消失。



我最后做的是完全分开商店(问题中建议的第一个解决方案)。我做了一个额外的ajax调用来获取jobId,而另一个是在JobConversation源中获取对话。这样的事情:

  axios.get(window.taxFyleApi +'api / platform / active-jobs-pick / layerConversation?jobId ='+ jobId)
.then((res)=> {
let job = res.data [0]; //返回只有一个项目的数组
let qBuilder = window .layer.QueryBuilder.messages()。forConversation(job.conversationId)...

我保留了很好的方式将AltContainer与我的组件一起使用并丢失所有的编排管道。现在,我认为最终的清晰度值得额外的后端调用。



我也意识到我 LIKE 它可以工作(就符号而言),并会询问@goatslacker,或者可能会自己动手做。我希望能够指定依赖关系商店上的exportAsync()方法。我希望能够说:

  class JobConvesationStore {
constructor(){
this.exportAsync(so urce,JobStore);
}

在JobStore拥有数据之前,不会调用异步方法JobConversationStore。意图易于阅读,不需要复杂的动作编排。


I'm using alt as my flux implementation for a project and am having trouble wrapping my head around the best way to handle loading stores for two related entities. I'm using sources feature along with registerAsync for to handle my async/api calls and bind them to my views using AltContainer.

I have two entities related one to one by the conversationId. Both are loaded via an api call:

Once my job store is loaded with data I want to fill a conversation store.

I use a source to load the job store:

module.exports = {
    fetchJobs() {
        return {
            remote() {
                return axios.get('api/platform/jobs');

            },....

Seems like a job for the waitFor() method, but it seems for use when the contents of one store require a transformation or merging with the contents of another. I need to fetch the contents of one data store based on the contents of another.

In general terms I need to:

  • Call a third party API and load a list of entities into a store.
  • When that data arrives I need to use attribute from each of the above to call another API and load that data into another store.

My naive solution is to reference the conversation actions from the job store and to dispatch an event when the data arrives. Something like this:

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);
    }
}

Of course, doing this, violates the dictum that stores shouldn't dispatch events, and so I must use defer to dispatch an action in the middle of a dispatch. It makes sense to me, since it seems in going down this path I'm reintroducing all sorts of side effects in my code; losing the beauty of the "functional pipelines" that I should be seeing with flux.

Also, my job store has to hold a reference to any dependent entities so it can dispatch the appropriate action. Here I have only one, but I could imagine many. In terms of the dependencies between entities this seems totally backwards.

A couple of alternatives come to mind:

I can call the api/platform/jobs endpoint in the source/action where I fetch all conversations, just to get the id. The original approach is more efficient, but this seems truer to the spirit of flux in that I lose all the cross-talk.

I could also have single action/source that fetches both, returning {jobs:{}, conversations: in the action} (orchestrating the dependency there using promises) and use this populate both stores. But this approach seems unnecessarily complicated to me (I feel like I shouldn't have to do it!).

But am I missing another way? It seems strange that such a common use case would break the elegance of the flux paradim and/or forces me to jump through so many hoops.

@dougajmcdonald posed a similar question here, but maybe it was phrased too generally, and didn't get any traction:

解决方案

I've been looking at @gravityplanx's answer, but am not sure how much it improves the situation.

To reiterate and amplify: I really, really like the alt pattern of loading my stores from a source. Every component that needs a store(s) looks something like so:

export default class extends React.Component {
    componentDidMount() {
        CurrentUser.fetch();
        Jobs.fetch(); 
    };
    render() {    
        return(
          <AltContainer stores={{user:CurrentUser, jobs:Jobs}}>
               <Body/>
          </AltContainer>)
    }

}

The intent is understandable at a glance. And I get a clean separation of concerns, making it easier to test my actions/stores, and sources.

But the beautiful pattern breaks down in the common use case from my question, and I wind up having to create some fairly complicated plumbing in my actions and stores to orchestrate the ajax calls for the conversations. The other answer seems to just shift this complexity elsewhere. I want it gone.

What I wound up doing was to completely separate the stores (the first solution suggested in the question). I make an extra ajax call to fetch the conversationId off the job and another to fetch the conversations in the JobConversation source. Something like this:

  axios.get(window.taxFyleApi + 'api/platform/active-jobs-pick/layerConversation?jobId=' + jobId)
            .then((res)=> {
                let job = res.data[0];  //Returns an array with only one item
                let qBuilder = window.layer.QueryBuilder.messages().forConversation(job.conversationId)...

I preserve the nice way of using AltContainer with my components and lose all the orchestration plumbing. Right now, I think the resultant clarity is worth the extra back end call.

I also realize how I'd LIKE it to work (in terms of notation), and will ask @goatslacker about, or may take a shot at doing it myself. I'd like to be able to specify the dependency in the exportAsync() method on a store. I'd love to be able to say:

class JobConvesationStore {
    constructor() {
        this.exportAsync(source, JobStore);
    }

The async method JobConversationStore would not be called until the JobStore had its data. The intent is easy to read and no complex action choreography would be needed.

这篇关于Flux / Alt数据依赖,如何优雅和惯用处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆