如何在多个视图中处理突变后的缓存更新?

How to handle cache update after mutation in multiple views?

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

虽然问题比较笼统,但我正在使用 React 和 apollo。

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

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

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

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

有更好的方法吗?

请注意,read/writeFragment 将不起作用,因为它们不会更新基础查询 - 例如检查此答案:

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

总而言之,我认为在这个设置中我会更好地处理全局状态并一起避免 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 值创建 post。

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

听起来您已经研究并使用了可以传递给从 useMutation 返回的突变函数的更新参数。您可能正在使用 proxy.readQuery 和 proxy.writeQuery 来更新它(或者让这种魔法在后台发生)。如果没有,这里是 documentation.

另一种概念相似但更详细的方法是使用 proxy.readFragment 和 proxy.writeFragment。您可以将类型的一组属性指定为片段的一部分,并在新数据进入时更新该片段。好的部分是该片段可以在任意数量的查询中使用,如果您更新片段,这些查询将会更新。

fragment documentations

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


CreateDraftPost突变的情况下:

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

PublishPost突变的情况下:

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

如何使用refetchQueries:

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