何时使用阿波罗的缓存重定向?



Apollo 文档讨论了如何使用cacheRedirects告诉 Apollo 如何从其他查询访问缓存中已有的数据。

它给出了一个例子:

在某些情况下,查询请求客户端中已存在的数据 存储在不同的密钥下。一个非常常见的例子是当 您的 UI 具有列表视图和详细信息视图,它们都使用相同的数据。 列表视图可能会运行以下查询:

查询列表视图 { 书籍 { 编号 标题 摘要 } }

选择特定书籍时,详细信息视图将显示 使用此查询的单个项目:

查询详细信息视图 { book(id: $id( { 编号 标题 摘要 } }

我们知道数据很可能已经在客户端缓存中,但是 因为它是使用不同的查询请求的,所以 Apollo 客户端不会 知道这一点。为了告诉阿波罗客户在哪里查找数据, 我们可以定义自定义解析器

我试图理解为什么这个例子是必要的。如果books查询返回一个类型为Book的数组,并且book请求返回一个类型为Book的对象,那么规范化缓存肯定已经具有基于类型名和 id 的每个书籍(来自 ListView 查询(的数据,并且DetailView查询可以直接使用该信息,而无需任何进一步的干预。相反,我们被告知要编写一些代码来帮助它:

const cache = new InMemoryCache({
cacheRedirects: {
Query: {
book: (_, args, { getCacheKey }) =>
getCacheKey({ __typename: 'Book', id: args.id })
},
},
});

在什么情况下,阿波罗客户无法自己弄清楚这一点,为什么?

看起来很明显和直观,给定一个像下面的查询,我们正在通过它的id属性获取单个Book对象。

query DetailView($id: ID) {
book(id: $id) {
id
title
abstract
}
}

但是,在此示例中,此处的参数名称(id(恰好与缓存(id(使用的属性的名称匹配。在惯例之外,没有什么说论点本身不能被称为bookIdbookIDsupercalifragilisticexpialidocious。即使查询返回Book类型并采用一个或多个参数,Apollo 也无法推断哪个参数实际上是缓存规范化中使用的 id。同样,如果存在其他参数,它们对于当前缓存的内容是否可以使用可能无关紧要 - 需要进一步的逻辑来确定这一点。

这里的另一个考虑因素是,除了选择性地将IntrospectionFragmentMatcher实例传递给您的InMemoryCache之外,Apollo 实际上并不知道它查询的端点的模式是什么。规范化中的缓存使用的类型是在使用__typename属性提取查询确定的。cacheRedirects的全部意义在于防止在一个或多个项已在缓存中时触发查询。但是,给定一个特定的查询,Apollo 无法知道它会返回特定类型,直到该查询返回之后。cacheRedirects提供了一种说"此查询将返回此特定类型"的方法,而无需首先触发查询。

只是一个事后的想法:这本质上是由于 GraphQL 设计。在 GraphQL 中,book(id)它的解析器可以自由地以他们喜欢的任何方式解释id。它只是一个带有单个参数的函数调用,恰好返回一个类型Book的实例。

GraphQL 实际上对 ID 没有任何说明。它只承认__typename是特殊的。

只有中继,在某种程度上是阿波罗,稍后添加了对象ID的概念。不过,他们采取了一些不同的方法,Relay强制要求你的GraphQL模式进入一个更严格的正式结构。

关于客户端无法使用模式,甚至还有额外的复杂性(另一个答案也提到了((因此客户端甚至不知道book将在不进行查询的情况下返回Book(。这再次遵循 GraphQL 规范。

最新更新