具有命名空间查询的 Apollo Client 3.0 缓存
Apollo Client 3.0 Cache with Namespaced Queries
我有一些关于如何将 apollo 客户端缓存与我们组织查询的特定方式相结合的问题。
因此,我们组织查询的方式是将对同一资源的查询分组在单个命名空间下。例如。我们有两个资源,users
和 accounts
,我们的查询看起来像这样。
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 的工作原理?
- 除了为查询类型
user
生成唯一 ID 之外,还有其他方法可以保留两种响应吗?
- 这样的命名空间查询是个好主意吗?
谢谢大家!
如您所见,结果将被不同的查询覆盖,因为缓存不知道查询在技术上总是 returns 相同的对象。
有两种解决方法:
您已经确定了第一个:给这些对象一个静态 ID 字段。这很丑陋。第二种是为 docs 中讨论的这些查询字段编写 merge
函数。一般来说,我不认为命名空间是个坏主意,但如您所见,您必须为架构中的基本 any 实体类型编写此合并函数。因此,我建议谨慎使用命名空间。
垃圾收集器在 Apollo 3 中也得到了一些更新。现在可以随时对其进行自定义和运行。您可以阅读有关 GC here 的更多信息。不再引用的对象可能会在缓存中保留一段时间。文档似乎没有指定 GC 运行 的时间。可以通过调用client.gc()
.
手动运行
实际上,在 Apollo 3 中使用命名空间查询的正确方法是将 keyFields
设置为空数组。
当你这样做时,你向 Apollo 表明没有用于合并的 id,因此所有内容都应该合并到同一个缓存键中。
您不必为此编写合并函数。
通过 typePolicies
选项配置 InMemoryCache
配置
const apolloClient = new ApolloClient({
cache: new InMemoryCache({
typePolicies: {
UserQueries: {
keyFields: [],
},
AccountQueries: {
keyFields: [],
},
},
}),
});
我有一些关于如何将 apollo 客户端缓存与我们组织查询的特定方式相结合的问题。
因此,我们组织查询的方式是将对同一资源的查询分组在单个命名空间下。例如。我们有两个资源,users
和 accounts
,我们的查询看起来像这样。
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 的工作原理? - 除了为查询类型
user
生成唯一 ID 之外,还有其他方法可以保留两种响应吗? - 这样的命名空间查询是个好主意吗?
谢谢大家!
如您所见,结果将被不同的查询覆盖,因为缓存不知道查询在技术上总是 returns 相同的对象。
有两种解决方法:
您已经确定了第一个:给这些对象一个静态 ID 字段。这很丑陋。第二种是为 docs 中讨论的这些查询字段编写 merge
函数。一般来说,我不认为命名空间是个坏主意,但如您所见,您必须为架构中的基本 any 实体类型编写此合并函数。因此,我建议谨慎使用命名空间。
垃圾收集器在 Apollo 3 中也得到了一些更新。现在可以随时对其进行自定义和运行。您可以阅读有关 GC here 的更多信息。不再引用的对象可能会在缓存中保留一段时间。文档似乎没有指定 GC 运行 的时间。可以通过调用client.gc()
.
实际上,在 Apollo 3 中使用命名空间查询的正确方法是将 keyFields
设置为空数组。
当你这样做时,你向 Apollo 表明没有用于合并的 id,因此所有内容都应该合并到同一个缓存键中。
您不必为此编写合并函数。
通过 typePolicies
选项配置 InMemoryCache
配置
const apolloClient = new ApolloClient({
cache: new InMemoryCache({
typePolicies: {
UserQueries: {
keyFields: [],
},
AccountQueries: {
keyFields: [],
},
},
}),
});