使用mobx进行延迟加载的惯用方法

时间:2016-09-07 12:05:42

标签: javascript reactjs lazy-loading mobx

使用MobX时,延迟加载属性的当前惯用方法是什么?

我已经在这几天苦苦挣扎了,而且我没有找到任何好的例子,因为严格的模式已成为一件事。我喜欢严格模式的想法,但我开始认为延迟加载与它不一致(访问或观察属性应该触发加载数据的副作用,如果它还没有)。

这是我的问题的症结所在,但看看我如何到这里继续阅读。

我当前设置的基础知识(不发布大量代码):

React Component 1(ListView): componentWillMount

  1. componentWillMount& componentWillReceiveProps - 组件从路径参数(react-router)获取过滤器值,将其保存为ListView上的可观察对象,并告诉商店根据它获取“提议”
  2. Store.fetchProposals检查是否已经发出了请求(请求存储在ObservableMap中,通过序列化过滤器对象,因此两个相同的过滤器将返回相同的响应对象)。如果需要,它会发出请求并返回包含有关请求是否已完成或有错误的信息的可观察响应对象。
    1. ListView将可观察的响应对象保存为属性,以便它可以显示加载或错误指示符。
    2. ListView有一个计算属性,使用用于获取的相同过滤器对象调用Store.getProposals
    3. Store.getProposals是一个转换器,它接受一个过滤器对象,从ObservableMap获取所有提议(在proposal.id上的键),使用过滤器对象过滤列表并返回一个Proposal [](如果没有与过滤器匹配则为空,包括尚未加载任何提案的内容)
  3. 这一切似乎都运作良好。

    问题是提案具有client和clientId的属性。 Proposal.clientId是一个加载了提案的字符串。我想等到实际访问客户端告诉商店从服务器获取它(假设它不在商店中)。在这种情况下,ListView恰好显示客户端名称,因此应在Proposal之后不久加载。

    我最接近的是在Proposal的构造函数列表中设置了一个自动运行,但其中一部分并没有在我无限的地方做出反应。 (截断到相关部分):

    @observable private clientId: string = '';
    @observable private clientFilter: IClientFilter = null;
    @observable client: Client = null;
    
    constructor(sourceJson?: any) {
        super(sourceJson);
        if (sourceJson) {
            this.mapFromJson(sourceJson);
        }
        //this one works. I'm turning the clientId string into an object for the getClients transformer 
        autorun(() => { runInAction(() => { this.clientFilter = { id: this.clientId }; }) });
        autorun(() => {
            runInAction(() => {
                if (this.clientId && this.clientFilter) {
                    const clients = DataStore.getClients(this.clientFilter);
                    const response = DataStore.fetchClients(this.clientFilter);
                    if (response.finishedTime !== null && !response.hasErrors) {
                        this.client = clients[0] || null;
                        console.log('This is never called, but I should see a client here: %o', DataStore.getClients(this.clientFilter));
                    }
                }
            })
        });
    }
    

    响应对象是可观察的:

    export class QueryRequest<T extends PersistentItem | Enum> {
        @observable startTime: Date = new Date();
        @observable finishedTime: Date = null;
        @observable errors: (string | Error)[] = [];
        @observable items: T[] = [];
        @computed get hasErrors() { return this.errors.length > 0; }
        @observable usedCache: boolean = false;
    }
    

    我感觉我正在与系统作战,并且在构造函数中设置autoruns似乎并不理想。有人以合理的方式解决这种模式吗?如果我的设置看起来很疯狂,我愿意接受有关整个事情的建议。

    编辑1:为清晰起见,删除了@Mobx。

    编辑2: 试图重新评估我的情况,我(再次)找到了优秀的lib mobx-utils,它具有lazyObservable功能,可满足我的需求。目前它看起来像这样:

    client = lazyObservable((sink) => {
        autorun('lazy fetching client', () => {
            if (this.clientFilter && this.clientFilter.id) {
                const request = DataStore.fetchClients(this.clientFilter);
                if (request.finishedTime !== null && !request.hasErrors) {
                    sink(request.items[0]);
                }
            }
        })
    }, null);
    

    这很有用!

    我想我需要在那里基于此对象clientId / clientFilter属性更新自动运行(如果此对象稍后被分配给新客户端,我希望更新lazyObservable)。我不介意一些懒惰属性的样板,但我肯定对那里的建议持开放态度。

    如果这最终成为了可行的方法,我也将从同一个lib而不是我的可观察请求对象中查看fromPromise。不确定因为我正在跟踪开始时间以检查陈旧性。链接到这里以防其他人没有遇到它:)

1 个答案:

答案 0 :(得分:2)

我一直在我的项目中使用不同的方法,并将其解压缩到一个单独的npm包中:https://github.com/mdebbar/mobx-cache

这是一个简单的例子:

首先,我们需要一个React组件来显示客户端信息:

@observer
class ClientView extends React.Component {
  render() {
    const entry = clientCache.get(this.props.clientId)

    if (entry.status !== 'success') {
      // Return some kind of loading indicator here.
      return <div>Still loading client...</div>
    }

    const clientInfo = entry.value
    // Now you can render your UI based on clientInfo.
    return (
      <div>
        <h2>{clientInfo.name}</h2>
      </div>
    )
  }
}

然后,我们需要设置clientCache

import MobxCache from "mobx-cache";

function fetchClient(id) {
  // Use any fetching mechanism you like. Just make sure to return a promise.
}

const clientCache = new MobxCache(fetchClient)

这就是你需要做的一切。 MobxCache会在需要时自动调用fetchClient(id)并为您缓存数据。