【问题标题】:Why react useQuery() doesnt fetch the newest data after a mutation?为什么react useQuery() 在突变后不获取最新数据?
【发布时间】:2021-10-27 20:53:37
【问题描述】:

我有这样的代码

const [inputComment, setInputComment] = useState('');

const [
  commentPost,
  { data: data4, loading: loading4, errorCreate4 },
] = useMutation(COMMENT_POST);

const { error: error2, loading: loading2, data: data2 } = useQuery(
  GET_POST_BY_ID,
  {
    variables: {
      postid: item.id,
    },
  },
);

const doComment = () => {
  commentPost({
    variables: {
      postId: item.id,
      userEmail: email,
      comment: inputComment,
    },
  })
    .then(({ data }) => {
      setInputComment('');
      console.log('success');
    })
    .catch((e) => {
      console.log('not success');
    });
};

这应该获取数据,当我发表评论时,它会运行突变并重新渲染所有内容。

我的问题是,它重新渲染好了,但是 useQuery 获取的数据不是最新数据,也就是我添加新评论之前的数据。

有人知道如何解决这个问题吗??

请帮忙:(

【问题讨论】:

  • 这个useQuery它来自哪个库?阿波罗还是反应查询?
  • 能否也包括您的 COMMENT_POST 和 GET_POST_BY_ID

标签: reactjs apollo react-apollo


【解决方案1】:

您的突变会修改服务器端上的数据。
修改完成后,您应该重新获取数据,以便在客户端的本地缓存中获取修改后的版本。

通过猜测您的变异和查询的实际工作方式,如下所示:

const [
  commentPost,
  { data: data4, loading: loading4, errorCreate4 },
] = useMutation(COMMENT_POST, {
  refetchQueries: [
    { query: GET_POST_BY_ID, variables: { postid: item.id } }
  ]
});

否则,您可以直接更新本地缓存,而不是从服务器重新获取。
更多信息可以在here in the official documentation找到。

【讨论】:

    【解决方案2】:

    我假设commentPost 是一个插入操作,而不是单个记录的更新。在这种情况下,Apollo useMutation 不会为你更新缓存。 您需要自己修改缓存。official Apollo documentation 已通过示例介绍了此用例。您可能还想修改writeFragment 的用法。

    以下内容直接来自关于列表字段缓存更新的 apollo 文档。

    在大多数情况下,突变响应应包括任何对象 突变修改。这使 Apollo Client 能够规范化那些 对象并根据它们的 __typename 和 id 字段缓存它们(通过 默认)。

    ...

    当一个突变的响应不足以更新所有修改过的 缓存中的字段(例如某些列表字段),您可以定义一个 更新功能以在 突变。

    const [addTodo] = useMutation(ADD_TODO, {
        update(cache, { data: { addTodo } }) {
          cache.modify({
            fields: {
              todos(existingTodos = []) {
                const newTodoRef = cache.writeFragment({
                  data: addTodo,
                  fragment: gql`
                    fragment NewTodo on Todo {
                      id
                      type
                    }
                  `
                });
                return [...existingTodos, newTodoRef];
              }
            }
          });
        }
      });
    

    编辑

    我注意到另一个答案建议使用 refetch,这对于初学者来说不是一个糟糕的选择。但是,更新缓存是推荐的方法而不是重新获取。可以参考阿波罗博客文章When To Use Refetch Queries in Apollo Client

    以下是本文中应注意的一些引语。

    如果您刚刚开始使用 GraphQL,我认为传递您希望在突变后重新运行的查询的心理模型很容易让您理解。

    ...

    这里的优点是这种方法很简单。缺点是当我们可能不需要时,我们会再次获取整个数据列表。

    ...

    为了更有效地利用带宽和网络往返,我们可以依靠缓存规范化和更新功能。

    【讨论】:

      猜你喜欢
      • 2021-03-28
      • 2021-02-05
      • 2020-03-23
      • 2021-03-28
      • 2019-03-26
      • 2019-11-17
      • 2020-10-22
      • 1970-01-01
      • 2021-06-08
      相关资源
      最近更新 更多