何时使用 Apollo 缓存重定向?

When to use Apollo's cacheRedirects?

Apollo 文档 discusses the use of cacheRedirects 告诉 Apollo 如何从其他查询访问缓存中已有的数据。

它给出了一个例子:

In some cases, a query requests data that already exists in the client store under a different key. A very common example of this is when your UI has a list view and a detail view that both use the same data. The list view might run the following query:

query ListView { books { id title abstract } }

When a specific book is selected, the detail view displays an individual item using this query:

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

We know that the data is most likely already in the client cache, but because it’s requested with a different query, Apollo Client doesn’t know that. In order to tell Apollo Client where to look for the data, we can define custom resolvers

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

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

ApolloClient 到底在什么情况下不能自己解决这个问题,为什么?

给定如下所示的查询,我们通过 id 属性.

获取单个 Book 对象,这似乎是显而易见且直观的
query DetailView($id: ID) {
  book(id: $id) {
    id
    title
    abstract
  }
}

然而,在这个例子中,这里的参数名称 (id) 恰好与缓存使用的 属性 的名称 (id) 匹配。在惯例之外,没有任何内容表明参数本身不能称为 bookIdbookIDsupercalifragilisticexpialidocious。即使查询 return 是 Book 类型并带有一个或多个参数,Apollo 也无法推断哪个参数实际上是缓存规范化中使用的 id。同样,如果存在其他参数,它们可能会或可能不会影响当前缓存的内容是否可以使用——需要进一步的逻辑来确定。

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

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

类型的实例

GraphQL 实际上对 ID 只字未提。它只将 __typename 识别为特殊。

只有 Relay,在某种程度上是 Apollo,稍后添加对象 ID 的概念。不过,他们采用了一些不同的方法,Relay 将您的 GraphQL 模式强制转换为更严格、更正式的结构。

关于模式对客户端不可用(因此客户端甚至不知道 book 将 return Book而不进行查询)。这再次遵循 GraphQL 规范。