问题描述
我在交互有了缓存的数据,尽管我了解cacheRedirects的工作原理,但首先我有点困惑.这是我问另一个问题的部分原因: do Apollo客户端缓存嵌套对象?
我们知道数据很可能已经在客户端缓存中,但是由于使用其他查询要求,Apollo客户端不知道.
为什么?
复制文档中的示例,为了清楚:
query ListView { books { id title abstract } } query DetailView { book(id: $id) { id title abstract } }
推荐答案
Apollo缓存它在归一化方式.
如果您的ListView返回数据,例如:
{ "data": { "books": [ { "id": 1, "title" "ABC", "__typename": "Book" }, { "id": 2, "title" "DEF", "__typename": "Book" } ] } }
每本书将根据其id和__typename(Book:1,Book:2等)存储在键下的缓存中.然后,此特定的缓存键列表与books根字段关联.如果您再次请求books,Apollo将看到它已经在缓存中具有该查询,并且会根据密钥列表重新创建结果.
如果books进行一些参数,则将每组参数视为不同的缓存条目. books(onSale: true)可能会返回与books(subject: "Computer Science")不同的书籍.每组缓存键分别存储.如果您运行第一个查询,然后第二个查询,第二个将是缓存失误,并且仍然会击中服务器.
同样,您可以有一个查询,该查询需要一些参数并返回一本书,例如book(id: 1).但是,在所有这些示例中,阿波罗都不"理解"参数id和onSale是什么.这些参数与返回的结果如何相关是您的业务逻辑的一部分.所有的阿波罗"知道"是给定此查询和这组参数,您会得到此特定对象或数组的对象.
作为一个人,我可以从命名中推断出一个像book(id: 2)的查询返回具有2 ID的单书.但是,像阿波罗这样的库无法准确地推断出该信息 - 它如何猜测该字段的正确类型或返回单个对象而不是一个对象数组?为此,如何推断id: 2转化为" book where id = 2"?毕竟,实际参数可以看多种方式:book(identifier: 2),book(filter: { id: 2 })等.
因此,我们使用cacheRedirects"教" Apollo如何查找可能已经存在的缓存中的数据.这有效地复制了通常位于服务器上的一些业务逻辑,但可以帮助我们避免对服务器进行其他调用.
问题描述
I read the docs on interacting with cached data and while I understand how cacheRedirects works, I'm a bit confused why it is needed in the first place. This is part of the reason why I asked this other question: Does the Apollo client cache nested objects in React?
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.
Why is that?
Copy-pasting the example in the docs, for clarity:
query ListView { books { id title abstract } } query DetailView { book(id: $id) { id title abstract } }
推荐答案
Apollo caches the data it receives in a normalized manner.
If your ListView returns data like:
{ "data": { "books": [ { "id": 1, "title" "ABC", "__typename": "Book" }, { "id": 2, "title" "DEF", "__typename": "Book" } ] } }
each book will be stored in the cache under a key based on its id and __typename (Book:1, Book:2, etc.). This particular list of cache keys is then associated with the books root field. If you request books again, Apollo will see it has that query in the cache already and will recreate the result based on the list of keys.
If books takes some arguments, then each set of arguments is treated as a different cache entry. books(onSale: true) might return a different set of books than books(subject: "Computer Science"). Each set of cache keys is stored separately. If you run the first query and then the second, the second will be a cache miss and will still hit the server.
Similarly, you can have a query that takes some arguments and returns a single book, like book(id: 1). In all these examples, though, Apollo doesn't "understand" what the arguments id and onSale are. How these arguments relate to the returned results is part of your business logic. All Apollo "knows" is that given this query and this set of arguments, you get this particular object or array of objects.
As a human, I can infer from naming that a query like book(id: 2) returns a single book with the id of 2. But there's no way for a library like Apollo to accurately infer that information -- how could it guess the correct type for the field or that it returns a single object instead of an array of objects? For that matter, how can it infer that id: 2 translates to "Book where id = 2"? After all, the actual arguments could look any number of ways: book(identifier: 2), book(filter: { id: 2 }), etc.
So we use cacheRedirects to "teach" Apollo how to look up data that may already be in our cache. This effectively duplicates some of the business logic that normally resides on the server, but helps us avoid an additional call to the server.