为什么 queryClient.setQueryData 在此示例中使用 react-query 花费这么长时间?

Why is queryClient.setQueryData taking so long in this example with react-query?

我正在使用 useQuery 和 setQueryData 使用 react-query 更新缓存,问题是 setQueryData 最多可能需要 2 分钟来更新数据,这可能是由于某种循环。我将每个页面映射到 'Styles' 数据,并使用响应中的数据更新与 pageIndex 匹配的页面上的样式、组和范围。我不知道为什么更新很长,我在这里使用 react-query 错了吗?顺便说一句,正在更新的数据一点也不大。

提前致谢。

export const useStyle = (styleId, pageIndex) => {
  const queryClient = useQueryClient();

  const { refetch } = useQuery('Style', () => fetchStyle(styleId), {
    staleTime: Infinity,
    refetchOnWindowFocus: false,
    initialData: {},
    onSuccess: (res) => {
      queryClient.setQueryData('Styles', (oldData) => ({
        pages: map(oldData.pages, (page, index) => ({
          ...page,
          ...(index === pageIndex
            ? {
              Styles: {
                ...page.Styles,
                ...res.Styles,
              },
              Groups: {
                ...page.Groups,
                ...res.Groups,
              },
              Ranges: {
                ...page.Ranges,
                ...res.Ranges,
              },
            }
            : {}),
        })),
        pagesParams: oldData.pageParams,
      }));
    },
  });

  return { refetchStyle: refetch };
};

我认为你在这里创建了一个无限循环:

  • useQuery('Styles') 订阅键 Styles,因此只要该键下缓存中的某些内容发生变化,此组件将始终更新/重新呈现
  • 在此查询的 onSuccess 中,您更新了同一个键 (Styles)
  • 此更新会通知所有观察者,因为他们应该知道这一变化
  • 调用 setQueryData 触发 onSuccess,因为 setQueryData 的处理方式与数据来自后端相同queryFn.
  • 这将再次触发您的 onSuccess,依此类推...

更好的问题是:你想解决什么问题?从表面上看,您希望在每次提取后执行一些数据转换。为此,您有多种选择,我已在此处详细概述了所有这些选择:https://tkdodo.eu/blog/react-query-data-transformations

但通常情况下,没有必要像那样合并数据。缓存最好是您从服务器获得的响应的 1:1 映射。

我已经通过使用 useMutation 而不是 useQuery 和 setQueryData 解决了这个问题,如果 onSuccess 循环是由 setQueryData 引起的,这是更好的方法。