首页 > 解决方案 > 为什么需要 refetchQueries?

问题描述

我正在关注关于 GraphQL 的教程,在视频中,作者没有将 refetchQueries 用于 deleteMutation,并且所有的 UI 更新和突变都可以正常工作。但是这里的项目沙箱代码已更新,refetchQuery 现在用于 Job 组件上的此操作 -> 第 20 行 -> deleteJob(): codeSandBox

我在我的应用程序中遇到了类似的问题,它不会自动更新 UI,而无需在任何地方完成 refetchQueries。如果我理解正确的话,Apollo 不应该通过 apollo-cache-inmemory 自动应用 Apollo 的缓存,在这种突变中执行突变和更新 UI。

开箱即用的 apollo-boost 示例:

export default gql`
mutation deleteItem($id: uuid!) {
  delete_item(where: {id:{_eq: $id }}){
    returning {
      id
    }
  }
}`;
 const onDeleteItem = (id) => {
    deleteItem({
      variables: { id },
    });
  };

对此有何建议或经验?

标签: reactjsgraphqlapolloapollo-client

解决方案


答案相对简单:GraphQL 中没有通用的方法来告诉客户端某个实体已被删除。让我们首先将其与更新突变进行比较。想象一下,我们正在更新缓存中已有的一项作业。首先是缓存(简化的,实际上并不是它在 Apollo 内部的样子):

{
  "Query": {
    "jobs": ["Job:1", "Job:2"],
  },
  "Job:1": {
    "__typename": "Job",
    "id": 1,
    "company": "Big Corp",
    "title": "Sales Specialist"
  },
  "Job:2": {
    "__typename": "Job",
    "id": 2,
    "company": "Big Corp",
    "title": "GraphQL Expert"
  }
}

如果 Apollo 现在从如下所示的更新突变中获得答案:

{
  "data": {
    "updateJob": {
      "__typename": "Job",
      "id": 2,
      "company": "Big Corp",
      "title": "GraphQL Unicorn"
    }
  }
}

它可以使用该dataIdFromObject函数来了解该对象属于"Job:2"我们规范化缓存中的缓存键。Apollo 可以假设此版本比旧版本更新,并根据较新结果的偏好合并密钥。我们的缓存现在看起来像这样:

{
  "Query": {
    "jobs": ["Job:1", "Job:2"],
  },
  "Job:1": { ... },
  "Job:2": {
    "__typename": "Job",
    "id": 2,
    "company": "Big Corp",
    "title": "GraphQL Unicorn" // updated!
  }
}

然后"jobs"查询将使用新作业自动更新,因为它只是引用作业而不存储实体本身。伟大的!但现在比较删除函数的结果:

{
  "data": {
    "deleteJob": {
      "returning": {
        "id": 2,
      }
    }
  }
}

这个查询的结果可以是任何东西。Apollo 无法知道您刚刚删除了具有特定 id 的作业。也许如果 GraphQL 在规范中有一些东西,比如神奇的“__isDeleted”,我们会得到类似的东西:

{
  "data": {
    "deleteJob": {
        "__typename": "Job",
        "__isDeleted": true,
        "id": 2,
      }
    }
  }
}

我们可以给我们的缓存实现一个提示,即__isDeleted: true应该从所有引用查询中删除实体。但不幸的是,这并不存在。不过这还不错,我们可以使用refetchQuery触发另一个查询的重新获取,或者我们可以手动更新另一个查询

const deleteJob = useMutation(DELETE_JOB, {
  update(store, response) {
    const data = store.readQuery({ query: GET_JOBS });
    data.jobs = data.jobs.filter(job => job.id !== response.deleteJob.returning.id);
    store.writeQuery({ query: GET_JOBS, data });
  }
});

推荐阅读