带有命名空间查询的 Apollo Client 3.0 缓存

Posted

技术标签:

【中文标题】带有命名空间查询的 Apollo Client 3.0 缓存【英文标题】:Apollo Client 3.0 Cache with Namespaced Queries 【发布时间】:2020-12-24 00:23:26 【问题描述】:

我有一些关于如何将 apollo 客户端缓存与我们组织查询的特定方式相匹配的问题。

因此,我们组织查询的方式是将同一资源上的查询分组到单个命名空间下。例如。我们有两个资源,usersaccounts,我们的查询看起来像这样。

type Query 
  user: UserQueries
  account: AccountQueries


type UserQueries 
  all: [User!]!
  byId(id: ID!): User


type AccountQueries 
  all: [Account!]!
  byId(id: ID!): Account


type User ...
type Account ...

由于Queries 类型都没有提供ID 字段,默认情况下UserQueries 下的第二个查询的响应将替换缓存中第一个查询的数据,即首先我进行all 查询,然后我' 将取回一些存储在缓存中 user 字段下的数据。然后如果我进行byId 查询,user 下缓存中的数据将被新数据替换。

关于这个过程的一些问题:

    我注意到,即使 all 数据被 byId 数据替换后,之前获取的用户(规范化的用户)仍然在缓存中可用,当我认为它们将被垃圾收集时,因为引用是丢失。垃圾收集器是否不会立即对它们进行垃圾收集,而是以一定的节奏运行?还是我完全误解了 gc 的工作原理? 除了为查询 typesuser 生成唯一 ID 之外,还有其他方法可以保留两个响应吗? 这样命名空间查询是个好主意吗?

谢谢各位!

【问题讨论】:

你知道多少好的命名空间 API? 【参考方案1】:

正如您所经历的,结果将被不同的查询覆盖,因为缓存不知道从技术上讲查询总是返回相同的对象。

有两种解决方案:

您已经确定了第一个:给这些对象一个静态 ID 字段。这很丑陋。第二个是为这些查询字段编写merge 函数,如docs 中所述。我不认为命名空间通常是一个坏主意,但正如您所看到的,您必须为架构中的基本 any 实体类型编写此合并函数。因此,我建议谨慎使用命名空间。

垃圾收集器在 Apollo 3 中也得到了一些更新。它现在可以自定义并随时运行。您可以阅读有关 GC 的更多信息here。不再引用的对象可能会在缓存中保留一段时间。文档似乎没有指定 GC 的运行时间。可以通过调用client.gc()手动运行。

【讨论】:

感谢@Herku!我们最终删除了命名空间,让我们的生活更轻松。【参考方案2】:

实际上,在 Apollo 3 中使用命名空间查询的正确方法是将 keyFields 设置为空数组。 当你这样做时,你向 Apollo 表明没有用于合并的 id,因此所有内容都应该合并到同一个缓存键中。 您不必为此编写合并函数。

InMemoryCache配置中通过typePolicies选项配置

const apolloClient = new ApolloClient(
  cache: new InMemoryCache(
    typePolicies: 
      UserQueries: 
        keyFields: [],
      ,
      AccountQueries: 
        keyFields: [],
      ,
    ,
  ),
);

【讨论】:

以上是关于带有命名空间查询的 Apollo Client 3.0 缓存的主要内容,如果未能解决你的问题,请参考以下文章

使用 Apollo Client GraphQL 查询和修改表单

带有 Apollo-Client 3 警告的 WebStorm 未知指令 @client

我可以覆盖组件中单个查询的 Apollo Client 标头吗?

如何与另一个查询共享缓存的 apollo-client 数据

是否可以使用 apollo-client 跳过部分查询

我正在将 vue 3 与 apollo/client 一起使用,但出现错误