【问题标题】:Auto-update of apollo client cache after mutation not affecting existing queries突变后自动更新 apollo 客户端缓存不影响现有查询
【发布时间】:2020-06-07 03:48:54
【问题描述】:

我有一个突变(UploadTransaction)返回某个名为 Transaction 的对象的某个列表。

#import "TransactionFields.gql" 
mutation UploadTransaction($files: [Upload!]!) {
  uploadFile(files: $files){
    transactions {
      ...TransactionFields
    }
  }
}

从后端(石墨烯)返回的交易有 id 和 typename 字段。因此它应该自动更新缓存中的事务。在 Apollo 的 chrome 开发工具中,我可以看到新的交易:

我还有一个获取所有 Transaction 对象的 GetTransactions 查询。

#import "TransactionFields.gql"
query GetTransactions {
  transactions {
    ...TransactionFields
  }
}

但是,我没有看到查询返回了新添加的事务。在初始加载期间,Apollo 客户端加载了 292 个事务,显示在 ROOT_QUERY 下。它不断返回相同的 292 笔交易。 UploadTransaction 突变在开发工具的缓存中添加“Transaction”类型的新对象,而不影响开发工具中的 ROOT_QUERY 或我在代码中的查询。

TransactionFields.gql 是

fragment TransactionFields on Transaction {
    id
    timestamp
    description
    amount
    category {
      id
      name
    }
    currency
}

知道我做错了什么吗?我是 apollo 客户端和 graphql 的新手

【问题讨论】:

    标签: graphql react-apollo apollo-client


    【解决方案1】:

    来自docs

    如果突变更新了单个现有实体,Apollo 客户端可以在突变返回时自动更新其缓存中该实体的值。为此,突变必须返回被修改实体的 id,以及被修改字段的值。方便的是,突变在 Apollo Client 中默认执行此操作...

    如果突变修改了多个实体,或者如果它创建或删除实体,Apollo 客户端缓存不会自动更新以反映突变的结果。解决这样,您对 useMutation 的调用可以包含更新函数。

    如果您有一个返回实体列表(例如,用户)然后创建或删除用户的查询,Apollo 无法知道该列表应该更新以反映您的突变。原因有两个

    • Apollo 无法知道什么突变实际上在做什么。它所知道的只是您请求的字段以及您传递这些字段的参数。我们可能会假设包含“插入”或“创建”等词的突变正在后端插入一些东西,但这不是给定的。
    • 没有办法知道插入、删除或更新用户应该更新特定查询。您的查询可能针对所有名为“Bob”的用户——如果您创建一个名为“Susan”的用户,则不应更新查询以反映该添加。类似地,如果突变更新了用户,则查询可能需要更新以反映更改。是否应该最终归结为只有您的服务器知道的业务规则。

    因此,为了更新缓存,您有两种选择:

    • 触发重新获取相关查询。您可以通过将refetchQueries 选项传递给useMutation 挂钩或manually calling refetch on those queries 来完成此操作。由于这需要向您的服务器发出一个或多个额外请求,因此它是较慢且更昂贵的选项,但在 A)您不想将一堆业务逻辑注入客户端或 B)更新时可能是正确的选择缓存复杂而广泛。
    • 为您的useMutation 钩子提供一个update 函数,告诉Apollo如何根据突变结果更新缓存。这样可以避免您发出任何额外的请求,但确实意味着您必须在服务器和客户端之间复制一些业务逻辑。

    文档中使用update 的示例:

    update (cache, { data: { addTodo } }) {
      const { todos } = cache.readQuery({ query: GET_TODOS });
      cache.writeQuery({
        query: GET_TODOS,
        data: { todos: todos.concat([addTodo]) },
      });
    }
    

    阅读文档了解更多详情。

    【讨论】:

    • 谢谢丹尼尔。我已经看到修改多个条目的突变需要更新功能。但是错过了创建/删除也需要它。
    • 有什么方法可以手动更新现有实体的缓存?
    猜你喜欢
    • 2020-02-03
    • 2021-10-06
    • 2021-03-11
    • 2018-12-19
    • 2021-04-27
    • 2020-11-27
    • 2018-11-02
    • 2020-05-09
    相关资源
    最近更新 更多