突变后自动更新 apollo 客户端缓存不影响现有查询

Auto-update of apollo client cache after mutation not affecting existing queries

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

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

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

我还有一个查询 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 的新手

来自docs

If a mutation updates a single existing entity, Apollo Client can automatically update that entity's value in its cache when the mutation returns. To do so, the mutation must return the id of the modified entity, along with the values of the fields that were modified. Conveniently, mutations do this by default in Apollo Client...

If a mutation modifies multiple entities, or if it creates or deletes entities, the Apollo Client cache is not automatically updated to reflect the result of the mutation. To resolve this, your call to useMutation can include an update function.

如果您查询 returns 实体列表(例如用户),然后创建或删除用户,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]) },
  });
}

阅读文档了解更多详细信息。