从 apollo-client 的客户端缓存中删除项目的正确方法
Correct way to remove item from client side cache in apollo-client
我在带有内存缓存的 React(Typescript) 应用程序中将 GraphQL 与 Apollo-Client 结合使用。缓存在添加新项目时更新,工作正常,没有错误。
删除项目时,会从 GraphQL Apollo-Server 后端返回一个字符串,说明删除操作成功,该操作会启动要调用的更新函数,该函数会读取缓存,然后通过过滤掉项目的 ID 来修改它。这是使用 Apollo-Client 的突变钩子执行的。
const [deleteBook] = useMutation<{ deleteBook: string }, DeleteBookProps>(DELETE_BOOK_MUTATION, {
variables: { id },
onError(error) {
console.log(error);
},
update(proxy) {
const bookCache = proxy.readQuery<{ getBooks: IBook[] }>({ query: GET_BOOKS_QUERY });
if (bookCache) {
proxy.writeQuery<IGetBooks>({
query: GET_BOOKS_QUERY,
data: { getBooks: bookCache.getBooks.filter((b) => b._id !== id) },
});
}
},
});
该功能有效,前端已使用缓存中的正确项目进行更新,但控制台中显示以下错误:
Cache data may be lost when replacing the getBooks field of a Query object.
To address this problem (which is not a bug in Apollo Client), define a custom merge function for the Query.getBooks field, so InMemoryCache can safely merge these objects:
existing: [{"__ref":"Book:5f21280332de1d304485ae80"},{"__ref":"Book:5f212a1332de1d304485ae81"},{"__ref":"Book:5f212a6732de1d304485ae82"},{"__ref":"Book:5f212a9232de1d304485ae83"},{"__ref":"Book:5f21364832de1d304485ae84"},{"__ref":"Book:5f214e1932de1d304485ae85"},{"__ref":"Book:5f21595a32de1d304485ae88"},{"__ref":"Book:5f2166601f6a633ae482bae4"}]
incoming: [{"__ref":"Book:5f212a1332de1d304485ae81"},{"__ref":"Book:5f212a6732de1d304485ae82"},{"__ref":"Book:5f212a9232de1d304485ae83"},{"__ref":"Book:5f21364832de1d304485ae84"},{"__ref":"Book:5f214e1932de1d304485ae85"},{"__ref":"Book:5f21595a32de1d304485ae88"},{"__ref":"Book:5f2166601f6a633ae482bae4"}]
For more information about these options, please refer to the documentation:
* Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers
* Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects
是否有更好的方法来更新缓存以便不会收到此错误?
我也遇到了完全相同的警告,不幸的是,除了此处建议的解决方案外,我没有想出其他解决方案:https://go.apollo.dev/c/merging-non-normalized-objects
const client = new ApolloClient({
....
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
getBooks: {
merge(existing, incoming) {
return incoming;
},
},
},
},
}
}),
});
(我不确定我是否正确地编写了您的字段和类型,因此您可以稍微更改此代码)
基本上,上面的代码让apollo客户端如何处理可合并数据。在这种情况下,我只是将旧数据替换为新数据。
不过,我想知道是否有更好的解决方案
我也遇到了同样的问题。我遇到了一个 GitHub 线程,它提供了两种替代解决方案 here。
首先是在调用 cache.writeQuery
:
之前清除缓存中的内容
cache.evict({
// Often cache.evict will take an options.id property, but that's not necessary
// when evicting from the ROOT_QUERY object, as we're doing here.
fieldName: "notifications",
// No need to trigger a broadcast here, since writeQuery will take care of that.
broadcast: false,
});
简而言之,这会刷新您的缓存,因此您的新数据将成为新的真相来源。不用担心丢失旧数据。
关于 apollo-client v3 的替代建议在下面 same thread:
cache.modify({
fields: {
notifications(list, { readField }) {
return list.filter((n) => readField('id', n) !==id)
},
},
})
这种方式删除了很多样板文件,因此您无需使用 readQuery
、evict
和 writeQuery
。问题是,如果您 运行ning 打字稿,您将 运行 陷入一些实施问题。在底层,使用的格式是 InMemoryCache
格式,而不是通常的 GraphQL 数据。您将看到 Reference
个对象、未推断的类型以及其他奇怪的东西。
我在带有内存缓存的 React(Typescript) 应用程序中将 GraphQL 与 Apollo-Client 结合使用。缓存在添加新项目时更新,工作正常,没有错误。
删除项目时,会从 GraphQL Apollo-Server 后端返回一个字符串,说明删除操作成功,该操作会启动要调用的更新函数,该函数会读取缓存,然后通过过滤掉项目的 ID 来修改它。这是使用 Apollo-Client 的突变钩子执行的。
const [deleteBook] = useMutation<{ deleteBook: string }, DeleteBookProps>(DELETE_BOOK_MUTATION, {
variables: { id },
onError(error) {
console.log(error);
},
update(proxy) {
const bookCache = proxy.readQuery<{ getBooks: IBook[] }>({ query: GET_BOOKS_QUERY });
if (bookCache) {
proxy.writeQuery<IGetBooks>({
query: GET_BOOKS_QUERY,
data: { getBooks: bookCache.getBooks.filter((b) => b._id !== id) },
});
}
},
});
该功能有效,前端已使用缓存中的正确项目进行更新,但控制台中显示以下错误:
Cache data may be lost when replacing the getBooks field of a Query object.
To address this problem (which is not a bug in Apollo Client), define a custom merge function for the Query.getBooks field, so InMemoryCache can safely merge these objects:
existing: [{"__ref":"Book:5f21280332de1d304485ae80"},{"__ref":"Book:5f212a1332de1d304485ae81"},{"__ref":"Book:5f212a6732de1d304485ae82"},{"__ref":"Book:5f212a9232de1d304485ae83"},{"__ref":"Book:5f21364832de1d304485ae84"},{"__ref":"Book:5f214e1932de1d304485ae85"},{"__ref":"Book:5f21595a32de1d304485ae88"},{"__ref":"Book:5f2166601f6a633ae482bae4"}]
incoming: [{"__ref":"Book:5f212a1332de1d304485ae81"},{"__ref":"Book:5f212a6732de1d304485ae82"},{"__ref":"Book:5f212a9232de1d304485ae83"},{"__ref":"Book:5f21364832de1d304485ae84"},{"__ref":"Book:5f214e1932de1d304485ae85"},{"__ref":"Book:5f21595a32de1d304485ae88"},{"__ref":"Book:5f2166601f6a633ae482bae4"}]
For more information about these options, please refer to the documentation:
* Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers
* Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects
是否有更好的方法来更新缓存以便不会收到此错误?
我也遇到了完全相同的警告,不幸的是,除了此处建议的解决方案外,我没有想出其他解决方案:https://go.apollo.dev/c/merging-non-normalized-objects
const client = new ApolloClient({
....
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
getBooks: {
merge(existing, incoming) {
return incoming;
},
},
},
},
}
}),
});
(我不确定我是否正确地编写了您的字段和类型,因此您可以稍微更改此代码)
基本上,上面的代码让apollo客户端如何处理可合并数据。在这种情况下,我只是将旧数据替换为新数据。
不过,我想知道是否有更好的解决方案
我也遇到了同样的问题。我遇到了一个 GitHub 线程,它提供了两种替代解决方案 here。
首先是在调用 cache.writeQuery
:
cache.evict({
// Often cache.evict will take an options.id property, but that's not necessary
// when evicting from the ROOT_QUERY object, as we're doing here.
fieldName: "notifications",
// No need to trigger a broadcast here, since writeQuery will take care of that.
broadcast: false,
});
简而言之,这会刷新您的缓存,因此您的新数据将成为新的真相来源。不用担心丢失旧数据。
关于 apollo-client v3 的替代建议在下面 same thread:
cache.modify({
fields: {
notifications(list, { readField }) {
return list.filter((n) => readField('id', n) !==id)
},
},
})
这种方式删除了很多样板文件,因此您无需使用 readQuery
、evict
和 writeQuery
。问题是,如果您 运行ning 打字稿,您将 运行 陷入一些实施问题。在底层,使用的格式是 InMemoryCache
格式,而不是通常的 GraphQL 数据。您将看到 Reference
个对象、未推断的类型以及其他奇怪的东西。