【问题标题】:Apollo client cache doesn't work as I excpectedApollo 客户端缓存无法按预期工作
【发布时间】:2018-10-02 05:45:07
【问题描述】:

我的问题:

我是 GraphQL 的新手,我正在使用 Apollo 服务器和客户端开发我的第一个全栈应用程序,这是一个简单的博客。

在客户端,我在两个不同的页面中使用相同的查询,但变量不同。查询是通过 ID 或 slug 查询博客文章,具体取决于我使用的页面。所以结果是一样的,只是查询变量发生了变化。

当我在一页中使用查询时,我认为查询不会在第二页上运行,因为 Apollo 缓存。但这不是正在发生的事情。查询在第二个中再次运行,当然返回的结果与其他页面中的结果相同。

为什么 Apollo 在这种情况下不使用缓存?

这是我使用的代码:

在服务器端,我有一个非常基本的查询来从博客中获取文章,可以通过 ID 或 Slug 获取:

type Query {
  ...
  article(id: ID, slug: String): Article
  ...
}

在客户端,如果文章已发布,我会通过 slug 查询文章,如果仍然是草稿,我会通过 ID 查询。

slug 查询:

<Query
  query={article}
  variables={{ slug }}
  fetchPolicy="cache-and-network"
>
  {({ loading, error, data }) => {
    return (
      <Article
        loading={loading}
        article={data && data.article}
      />
    );
  }}
</Query>

ID查询是一样的,只是变量param使用ID:

<Query
  query={article}
  variables={{ id }}
>
  {({ loading, error, data }) => {
    return (
      <EditArticle loading={loading} article={data && data.article} />
    );
  }}
</Query>

如您所见,两者都使用相同的 GraphQL 端点,结果是相同的。但是没有使用缓存。

【问题讨论】:

    标签: graphql apollo react-apollo apollo-client


    【解决方案1】:

    Apollo 假设您的解析器是纯的(它们没有副作用,并且在给定相同的输入/参数的情况下通常返回相同的结果)。这已经是很多假设了。想象一个解析器,它返回一个随机数或新闻网站上的最新评论。给定相同的输入,两者并不总是返回相同的结果。另一方面,Apollo 不会——也几乎不能——对你的解析器的实现做出假设。虽然在您的脑海中,文章解析器的实现是显而易见的(如果 id 存在,则返回具有该 ID 的文章,如果 slug 存在,则返回带有该 slug 的文章),这需要计算机程序来猜测.

    我已回复similar question recently。为了防止第二个查询运行,您必须实现cache redirect。缺点是您必须使客户端上的缓存重定向和服务器上的解析器保持同步。

    【讨论】:

    • 你说得对,几个小时前我才意识到 Apollo 对我的服务器端解析器一无所知,也不知道查询将返回相同的结果。我可能假设这是因为我来自 Meteor,其中客户端和服务器通过 DDP “绑定”。我不知道缓存重定向(直到这部分才阅读文档),所以当我收到第一个查询时,我使用client.writeQuery() 函数将第二个查询的结果写入缓存中。我想这和缓存重定向很相似。
    • 你有我的查询的缓存重定向示例吗?它似乎与 ID 配合得很好,但我不知道如何使它与 slug 一起工作......
    • 这确实看起来相当困难。我认为有一种简单的方法可以获取具有特定类型名称的所有元素,然后您可以使用Array.prototype.find 找到正确的元素。也许你可以尝试在slack 上问他们
    【解决方案2】:

    我遇到了同样的问题。从本质上讲,我希望缓存查找在尝试仅使用“slug”进行查找时会失败,我对此很好,但是它无法生成正确的搜索结果并且“null”结果返回为查询响应就好像它是一个成功的查询响应一样。哎呀。

    为了避免副作用,我将只使用一个单独的 graphQL 查询,它接受 slug 而不是 ID。这还有其他几个好处,例如,我可以在各自的查询中将该字段强制为“必需”。主要是它使基于 ID 的查询更具确定性,因此与缓存更兼容。

    type Query {
      ...
      article(id: ID!): Article
      articleBySlug(slug: String!): Article
      ...
    }
    

    更好的是能够使用您的“slug”值搜索缓存以获得匹配结果,但如果不使用“slug”作为缓存 ID 本身的一部分,这似乎尚不受支持。

    【讨论】:

      猜你喜欢
      • 2017-03-18
      • 2023-03-13
      • 2020-07-31
      • 2021-04-21
      • 2020-11-03
      • 2017-11-15
      • 1970-01-01
      • 2021-03-11
      相关资源
      最近更新 更多