我的问题:
我是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端点,结果相同。但是没有使用缓存。
答案 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本身的一部分,似乎尚不支持。