为什么需要refetchQueries? [英] Why is refetchQueries needed?

查看:226
本文介绍了为什么需要refetchQueries?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在关注有关GraphQL的教程,在视频中,作者没有将refetchQueries用作deleteMutation,并且所有方法都可以很好地与UI更新和突变配合使用.但是在此项目中,沙箱代码已更新,现在将refetchQuery用于作业组件上的此操作->第20行-> deleteJob():解决方案

答案是相对简单的: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,
      }
    }
  }
}

此查询的结果可以是任何值.阿波罗不知道您刚刚删除了具有特定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 }); } });

I am following a tutorial on GraphQL, in the video the author does not use refetchQueries for a deleteMutation and all works well with UI updates and mutation. But here in the project sandbox code is updated and refetchQuery is now used for this operatio on Job component -> line 20 -> deleteJob(): codeSandBox.

I have this similar problem in my app that does not update the UI automatically without refetchQueries done everywhere. Shouldn't Apollo be applying automatically the cache of Apollo via apollo-cache-inmemory, perform mutation and update UI in this kind of mutation if I understand it right.

Example out of the box with apollo-boost:

export default gql`
mutation deleteItem($id: uuid!) {
  delete_item(where: {id:{_eq: $id }}){
    returning {
      id
    }
  }
}`;

 const onDeleteItem = (id) => {
    deleteItem({
      variables: { id },
    });
  };

Any suggestions or experiences on this?

解决方案

The answer is relatively simple: There is no universal way in GraphQL to tell a client that an entity was deleted. Let's first compare this to an update mutations. Imagine we are updating one of the jobs that we already have in our cache. First the cache (simplified, not actually quite how it looks inside of 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"
  }
}

If Apollo now gets an answer from an update mutation that looks like the following:

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

It can use the dataIdFromObject function to understand that the object belongs to the cache key "Job:2" in our normalised cache. Apollo can assume that this version is newer than the old one and merge the keys with preference of the newer result. Our cache now looks like this:

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

Then the "jobs" query will automatically update with the new job because it is just referencing the job and is not storing the entity itself. Great! But now compare the result from the delete function:

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

The result of this query could be anything. Apollo cannot know that you have just deleted a job with a certain id. Maybe if GraphQL had something in the specification like a magical "__isDeleted" and we would get something like:

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

We could give our cache implementation the hint that entities with __isDeleted: true should be removed from all referencing queries. But unfortunately this does not exists. This is not to bad though, we can either use refetchQuery to trigger a refetch of the other query or we can manually update the other query:

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 });
  }
});

这篇关于为什么需要refetchQueries?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆