Graphql 阿波罗客户端缓存没有';I don’我没料到会工作

Graphql 阿波罗客户端缓存没有';I don’我没料到会工作,graphql,apollo,react-apollo,apollo-client,Graphql,Apollo,React Apollo,Apollo Client,我的问题: 我是GraphQL的新手,我正在使用Apollo服务器和客户端开发我的第一个全栈应用程序,这是一个简单的博客 在客户端,我在两个不同的页面中使用相同的查询,但变量不同。查询是按ID或slug查询博客文章,具体取决于我使用的页面。结果是一样的,只是查询变量发生了变化 当我在一个页面中使用查询时,我认为查询不会在第二个页面上运行,因为Apollo缓存。但事实并非如此。查询在第二个页面中再次运行,当然返回的结果与另一个页面中的结果相同 为什么阿波罗在这种情况下不使用缓存 以下是我使用的代码

我的问题:

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

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

当我在一个页面中使用查询时,我认为查询不会在第二个页面上运行,因为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端点,结果是相同的。但是缓存没有被使用。

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


我已经回答了一个问题。要防止第二个查询运行,必须实现一个。缺点是您必须使客户端上的缓存重定向与服务器上的解析程序保持同步

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

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

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

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

没错,我几个小时前才意识到Apollo对我的服务器端解析器一无所知,并且无法知道查询将返回相同的结果。我可能认为这是因为我来自Meteor,在那里客户端和服务器通过DDP“绑定”。我不知道缓存重定向(直到这一部分才阅读文档),所以当我收到第一个查询时,我使用
client.writeQuery()
函数在缓存中写入第二个查询的结果。我想这和缓存重定向很相似。你能给我的查询举个缓存重定向的例子吗?它似乎可以很好地与ID配合使用,但我不知道如何让它与Slug配合使用……这确实看起来相当困难。我认为有一种简单的方法可以获取所有具有特定类型名的元素,从中可以使用
Array.prototype.find
找到正确的元素。也许你可以试着问问他们