Apollo客户端缓存并不像我所想的那样工作

时间:2018-04-21 20:00:50

标签: graphql apollo react-apollo apollo-client

我的问题:

我是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的查询是相同的,除了使用ID的变量param:

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

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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

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

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

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

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