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

标签 javascript reactjs lazy-loading mobx

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

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

这是我问题的症结所在,但要了解我是如何走到这里的,请继续阅读。

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

React 组件 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[](如果没有匹配过滤器则为空,包括如果尚未加载任何提案)

这一切似乎都运作良好。

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

我最接近的是在提案的构造函数列表中设置一个自动运行,但它的一部分并没有在我打算的地方使用react。 ( chop 为相关部分):

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

我感觉我在与系统作斗争,无论如何在构造函数中设置自动运行似乎并不理想。有人以合理的方式解决这个模式吗?如果我的设置看起来很疯狂,我愿意接受关于整个事情的建议。


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


编辑 2: 试图重新评估我的情况,我(再次)找到了优秀的库 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)。我不介意为惰性属性提供一些样板,但我绝对乐于接受那里的建议。

如果这最终是要走的路,我也会看看 fromPromise来自同一个库而不是我的可观察请求对象。不确定,因为我正在跟踪开始时间以检查是否过时。链接在这里以防其他人没有遇到它:)

最佳答案

我一直在我的项目中使用不同的方法,并将其提取到一个单独的 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) 并为您缓存数据。

关于javascript - 使用 mobx 进行延迟加载的惯用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39369506/

相关文章:

javascript - React 函数组件中不检查 Null 条件

lazy-loading - ngrx 延迟加载访问根状态

javascript - 计算价格

javascript - 引用错误: folders is not defined vue:6

javascript - 为什么在实现全局作用域状态时我会在 react 中使用 'useReduce'?

javascript - React.js 应用程序在服务器中作为空白页面打开,而在本地运行良好

lazy-loading - 如何在光滑 slider 中延迟加载图片元素?

php - 如何从 mysql 数据库延迟加载项目,如 facebook 和 twitter(无限滚动)

javascript - 计算函数执行时间

javascript - 使用 Javascript 获取 Canvas 中的最大字体大小