Apollo 客户端缓存无法正常工作

Apollo client cache doesn't work as I excpected

我的问题:

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

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

当我在一页中使用查询时,我认为由于 Apollo 缓存,查询不会在第二页上 运行。但这不是正在发生的事情。第二个查询再次 运行s,当然 returns 我的结果与另一页中的结果相同。

为什么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查询是一样的,除了使用ID的变量参数:

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

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

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

我已经回答了 . To prevent the second query from running you have to implement a cache redirect。缺点是您必须保持客户端上的缓存重定向和服务器上的解析器同步。

我也遇到了同样的问题。本质上,我希望缓存查找在尝试仅使用 "slug" 进行查找时会简单地失败,我对此很好,但它无法生成正确的搜索结果和 "null"结果是 return 作为查询响应,就好像它是一个成功的查询响应一样。哎呀

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

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

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