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本身。
我的问题:
我是 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 的文章)这需要计算机程序进行大量猜测。
我已经回答了
我也遇到了同样的问题。本质上,我希望缓存查找在尝试仅使用 "slug" 进行查找时会简单地失败,我对此很好,但它无法生成正确的搜索结果和 "null"结果是 return 作为查询响应,就好像它是一个成功的查询响应一样。哎呀
为了避免副作用,我将只使用一个单独的 graphQL 查询,它接受 slug 而不是 ID。这还有其他一些好处,例如,我可以在各自的查询中将该字段强制为 "required"。主要是它使基于 ID 的查询更具确定性,因此与缓存更兼容。
type Query {
...
article(id: ID!): Article
articleBySlug(slug: String!): Article
...
}
更好的是能够使用 "slug" 值搜索缓存以获得匹配结果,但如果不使用 "slug" 作为缓存的一部分,这似乎还不受支持ID本身。