首页 > 解决方案 > 如何在多个视图中处理突变后的缓存更新?

问题描述

这更像是一个悬而未决的问题,但希望它不会被删除。

我正在使用 react 和 apollo,尽管问题更笼统。

假设我的应用中有 3 个不同的视图,它们都使用相似(但不相同)的数据。它们都使用单独的查询,但每个查询都使用通用操作,但返回的数据略有不同。

假设我在某处有一个突变,它向数据添加了一些东西(想想一个项目列表和一个正在添加的新项目)。

假设在突变后我想更新缓存以反映该更改。我正在使用 read/writeQuery 进行更新。使用此设置,我需要更新 3 个查询 - 这将成为维护的噩梦。

经过一番阅读,我认为我做错了——我现在创建了一个查询——现在我只需要在突变后更新那个单一的查询,我的所有视图都会自动更新。然而问题是这个查询现在必须下载所有 3 个视图组合所需的所有数据 - 感觉这非常低效,因为一些视图将获得他们永远不会使用的数据。

有更好的方法吗?

请注意,这read/writeFragment不起作用,因为它们不会更新基础查询-例如检查此答案:https ://stackoverflow.com/a/50349323/2874705

如果您需要更具体的示例,请在评论中告诉我。

总而言之,我认为在这个设置中我会更好地处理全局状态并避免一起使用 apollo 缓存 - 但是我觉得被骗了,因为 apollo 承诺解决状态问题:)

编辑

这是一个具体的例子:

假设我们的 graphql 模式是这样定义的:

type Post {
    id: ID!
    title: String!
    body: String
    published: Boolean!

}

type Query {
    posts(published: Boolean): [Post!]!
}


type Mutation {
  createDraft(body: String!, title: String!): Post
  publish(id: Int!): Post
}

现在,我们在客户端创建 3 个查询和 2 个突变

query PostTitles {
    posts {
        id
        title
    }
}

query Posts {
    posts {
        id
        title
        body
        published
    }
}

query PublishedPosts {
    posts (published: true) {
        id
        title
        body
        published
    }
}

mutation CreateDraftPost ($body: String!, $title: String!) {
    createDraft(body: $body, title: $title) {
        id
        title
        body
        published
    }
}

mutation PublishPost ($id:ID!) {
    publish (id: $id) {
        id
        published
    }
}

请注意createDraft,使用默认值创建帖子false published

如何使用这些突变中的任何一个来创建或发布帖子并在不使用refetchQueries或手动更新每个查询的情况下更新所有 3 个缓存查询?我认为真正的问题是这些查询中的每一个都单独存储在 apollo 内存缓存中。

标签: reactjsapolloreact-apolloapollo-client

解决方案


根据我的经验,它应该是这样的。


CreateDraftPost突变的情况下:

  1. 您调用突变并传递一个update函数。在此函数中,您通过创建一个新片段来update修改根查询的缓存,然后将此片段添加到. 看到这个:https ://www.apollographql.com/docs/react/data/mutations/#making-all-other-cache-updatespostsPostposts
  2. 由于PostTitlesand Postsall 依赖于根查询(只是查询的字段不同)并且您刚刚添加posts的新片段具有足够的字段,因此您的and应该自动反映更改。PostpostsPostTitlesPosts
  3. 因为CreateDraftPost总是创建一个published默认为false. 您不需要更新与PublishedPosts查询相关的任何内容。

PublishPost突变的情况下:

  1. 您调用突变,返回的结果是Post带有更新字段 ( id, published) 的结果。通过 Apollo GraphQL 缓存的机制,这个Post(由 标识id)将在它涉及的任何查询中更新。看到这个:https ://www.apollographql.com/docs/react/data/mutations/#updating-a-single-existing-entity
  2. 但是,您需要手动更新PublishedPost查询。update通过在突变调用中提供函数来做到这一点。在此update函数中,您将首先从返回的数据readQueryPublishedPost创建一个新Post数据,最后writeQuery将此帖子添加到PublishedPost结果中。参考这个:https ://www.apollographql.com/docs/react/caching/cache-interaction/#combining-reads-and-writes

如何使用refetchQueries

  • CreateDraftPost突变的情况下,仅重新获取Posts查询应该就足够了(PostTitles应该相应地更新),因为两者都Posts依赖PostTitles于相同的根查询posts,并且其中的字段Posts也涵盖了PostTitles
  • PublishPost突变的情况下,我宁愿重新获取PublishedPost查询以避免做整个update事情(因为我很懒,我认为重新获取 1 个查询不会花费我太多)

推荐阅读