【问题标题】:Load data from relay store while the query is loading在加载查询时从中继存储加载数据
【发布时间】:2019-05-04 08:54:11
【问题描述】:

我有一个共同的 HeaderFooter 显示可能已经在中继存储中的数据,而主要的 PageComponent 期望来自“查询”的数据,但我不想显示完整的加载屏幕给用户,我想在中间显示页眉、页脚和加载屏幕或内容。

所以,如您所知,如果我将所有内容包装在 QueryRenderer 中,我将有两个选择:查询正在“加载”或数据可用:

<QueryRenderer
  {...usualProps}
  render={({ error, props }) => {
    <div className="app-wrapper">
      { props || error ? <PageComponent {...props} error={error} /> : <div>Loading...</div>}
    </div>
  }}
/>

假设我有一种方法可以手动从存储中检索数据(因为我们没有从存储中进行部分渲染之类的东西),我可以将该信息传递给常见的 HeaderFooter,而主要查询正在加载:

<QueryRenderer
  {...usualProps}
  render={({ error, props }) => {
    <div className="app-wrapper">
      <Header {...storeProps} {...props} />
      { props || error ? <PageComponent {...props} error={error} /> : <div>Loading...</div>}
      <Footer {...storeProps} {...props} />
    </div>
  }}
/>

我发现既然我有环境,我可以做这样的事情来从商店获取信息:

const storeProps = relayEnvironment.getStore().lookup({
  dataID: 'client:root',
  node: query().fragment, // special query with only the information I need for the `Header`
  variables: {}
});

但是我有几个问题:

  • QueryRenderer 在卸载时处理数据 :cry: (虽然我从中读取的信息也应该由 Query 检索,但从存储中读取更像是查询返回时的后备)
  • 语法看起来很老套
  • 我必须创建一个查询并编译它(无论如何我都可以忍受)

可能我以错误的方式解决问题,也许有人做了类似的事情,可以给我一些建议。 (如果没有任何效果,我的计划 B 是使用 getDerivedStateFromProp 将查询信息发送到自定义上下文并将其保存在那里以避免存储 GC 问题,例如)。

TL:DR:我想在查询完成加载时从存储中加载数据,然后使用查询返回的数据。

有什么想法吗?如果有不清楚的地方请告诉我

【问题讨论】:

  • 当查询未完成时,props 将返回 null,您可以将其用作加载状态吗?喜欢if (!props) return &lt;Loading /&gt;

标签: relayjs relay relaymodern


【解决方案1】:

Relay 有 Observables 和 Cache 可以结合使用来实现这一点。

您可以从 'relay-runtime' 导入 { QueryResponseCache };

然后像这样使用它:

const cache = new QueryResponseCache({
      size: CACHE_SIZE, // Number of responses to cache
      ttl: CACHE_DURATION, // duration in ms to keep the cache
    })

现在,当您从服务器获得响应时,您可以像这样存储它

cache.set(queryId, variables, payload)

读起来像:

cache.get(queryId, variables)

现在对于 observable,从 'relay-runtime' 导入 { Observable };

然后你像这样在你的网络中使用它:

const fetchQuery = (operation, variables) => {
    return Observable.create(observer => {
      if (operation.operationKind !== 'mutation') {
        observer.next(cachedData) // cacheData fetched from cache
      }
      const jsonResponse = fetch(...);
      observer.next(jsonResponse);
      observer.complete();
    });
  };

现在,如果您想重用来自另一个查询的数据,那么缓存的情况可能不适用于您。但是如果你能够从 store 中获取数据,你应该能够在从服务器获取响应之前使用 observable 传递数据。

编辑

自最初回复以来,Relay 添加了一些新功能,现在可以像这样实现相同的功能:

// Create relay environment
const environment = new Environment({
  network: Network.create(/*...*/),
  store,
  gcReleaseBufferSize: 10, // Relay will cache the 10 latest responses
});

// Then set fetchPolicy on your QueryRenderer

<QueryRenderer {...otherProps} fetchPolicy="store-and-network" />

如果可用,中继现在将使用来自存储的响应,当响应从服务器返回时,使用来自服务器的响应。

【讨论】:

  • 我不太了解 Observables,我觉得这有点令人困惑
  • 我用不使用 Observables 的解决方案更新了响应。
【解决方案2】:

使用relayEnvironment 阅读商店听起来不是一个好的解决方案。 如果你为Header 加上一个QueryRenderer,为Footer 加上另一个,你会怎么想?因此,每个人都将获取自己的数据,与页面内容分开。这有意义吗?

希望对你有帮助:)

【讨论】:

  • 如果真的对您有用,您能否标记为最佳答案?谢谢:)
  • 嗨!抱歉延迟 - 这实际上并不能解决问题(尽管它有效),因为这将触发多个查询(每个查询渲染一个,所以至少两个)。
  • 嗯,是的。根据具体情况,我不认为这是一件坏事。
猜你喜欢
  • 1970-01-01
  • 2015-07-31
  • 1970-01-01
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 2020-07-24
  • 2012-07-23
  • 2015-01-19
相关资源
最近更新 更多