Apollo文档discusses the use of cacheRedirects
告诉Apollo如何通过其他查询访问缓存中已存在的数据。
它给出了一个例子:
在某些情况下,查询会请求客户端中已经存在的数据 使用其他密钥存储。一个很常见的例子是 您的用户界面具有使用相同数据的列表视图和详细信息视图。 列表视图可能会运行以下查询:
query ListView {图书{ ID 标题 摘要}}
选择特定书籍后,详细信息视图会显示一个 使用此查询的单个项目:
查询DetailView {图书(id:$ id){ ID 标题 摘要}}
我们知道数据很可能已经在客户端缓存中,但是 因为是通过其他查询请求的,所以Apollo Client不会 我知道。为了告诉Apollo Client在哪里寻找数据, 我们可以定义自定义解析器
我试图理解为什么对于本示例来说这是必需的。如果books
查询返回的类型为Book
的数组,并且book
请求返回的类型为Book
的单个对象,则肯定归一化的高速缓存将已经具有每个数据(来自ListView查询)基于类型名称和ID的书籍,DetailView
查询可以直接使用该信息,而无需任何进一步干预。相反,我们被告知编写一些代码来帮助它:
const cache = new InMemoryCache({
cacheRedirects: {
Query: {
book: (_, args, { getCacheKey }) =>
getCacheKey({ __typename: 'Book', id: args.id })
},
},
});
究竟是什么情况下ApolloClient无法自行解决?为什么?
答案 0 :(得分:2)
显而易见,直观的是,像下面这样的查询,我们通过其Book
属性来获取单个id
对象。
query DetailView($id: ID) {
book(id: $id) {
id
title
abstract
}
}
但是,在此示例中,此处的参数名称(id
恰好与高速缓存使用的属性的名称(id
)相匹配。除非另有约定,否则没有什么说法不能将参数本身称为bookId
,bookID
或supercalifragilisticexpialidocious
。即使查询返回Book
类型并接受一个或多个参数,Apollo也无法推断哪个参数实际上是缓存规范化中使用的ID。同样,如果存在其他参数,则在是否可以使用当前缓存的内容方面,它们可能无关紧要-尚需进一步的逻辑才能确定。
这里的另一个考虑是,除了有选择地将IntrospectionFragmentMatcher
的实例传递给您的InMemoryCache
外,Apollo实际上并不知道所查询的端点的模式是什么。 在之后,使用__typename
属性获取查询后,确定缓存中归一化使用的类型。 cacheRedirects
的全部要点是,如果一项或多项已在缓存中,则可以防止触发查询。但是,给定特定查询,Apollo无法知道它将返回特定类型,直到该查询返回。 cacheRedirects
提供了一种方式来表示“此查询将返回此特定类型”,而无需首先触发查询。
答案 1 :(得分:0)
只是事后的想法:这本质上是由于GraphQL设计所致。在GraphQL中,book(id)
的解析器可以随意使用自己喜欢的任何方式来解释id
。这只是一个带有单个参数的函数调用,碰巧会返回一个Book
类型的实例。
GraphQL实际上什么也没说。它仅将__typename
识别为特殊字符。
仅中继,并且在某种程度上是Apollo,稍后再添加对象ID的概念。但是,它们采取了一些不同的方法,其中Relay将您的GraphQL模式强制为一个更严格的正式结构。
对于客户机不可用的架构,甚至还有其他复杂性(也由其他答案提到)(客户机甚至不知道book
将不进行查询就返回Book
)。再次遵循GraphQL规范。