问题描述
- 可以进行查询以从特定的
Website
中检索子资源 - Apollo 服务器不是将
Website
ID 作为输入参数传递,而是从 HTTP 标头或 cookie 中检索 ID。 - 因此查询看起来像这样:
query {
currentWebsite {
id
...sub-resources
}
}
在当前网站更改之前,此方法运行良好。这是因为 Apollo 客户端已经在缓存中拥有一个网站,并且将从缓存中检索第一个(并且不正确的)网站,而不是发出另一个 HTTP 请求。我相信这是因为查询不包含唯一 ID,因此它将所有 currentWebsite
查询视为相同。
现在我知道有很多方法可以解决这个问题。以下是我所知道的方法以及明显的缺点:
- 更新 Apollo 服务器以允许接收
websiteId
作为输入参数。我测试了这个并且它有效。不幸的是,更新 API 需要做很多工作。 - 将
fetchPolicy
从默认值更改为类似cache-and-network
的内容。这是一个快速解决方案,但会发出比需要更多的 HTTP 请求。 - 在网站更改时手动使部分缓存失效。这是我最不喜欢的解决方案。
- 手动从缓存中读取。如果查询不存在,请使用
useQuery
之类的 fieldPolicy 调用network-only
。这感觉很沉重。
最终,我认为这些解决方案中的任何一个都不是我所需要的。我觉得必须有一种方法可以为 Apollo 缓存每个查询的网站 ID,以便它可以自行确定是应该从缓存中检索网站还是获取一个新网站。我发现 Apollo 缓存相当不透明,但不知道从哪里开始!
解决方法
所以这里的技巧是编写一个 custom keyArgs
function 并利用您可以拥有不传递给服务器的客户端变量这一事实:
query GetWebsiteById($websiteId: String) {
currentWebsite {
id
...sub-resources
}
}
当您执行查询时,将您拥有的任何标头值传递给 $websiteId
。然后您可以在 keyArgs
函数中读取该变量。
const createCache = () => new InMemoryCache({
typePolicies: {
Query: {
fields: {
currentWebsite: {
keyArgs: (_,{ variables }) => {
if (variables?.websiteId == null) {
return 'currentWebsite';
} else {
return `currentWebsite:${variables.websiteId}`;
}
}
}
}
}
}
});
现在它将使用自己唯一的 id 将每个查询存储在缓存中:currentWebsite:1
、currentWebsite:2
等。