反应查询获取旧数据

react-query getting old data

我有一个包含项目列表的母版页,以及一个我可以在其中获取和更新项目的详细信息页面。我有以下基于反应查询库的挂钩:

const useItems = (options) => useQuery(["item"], api.fetchItems(options)); // used by master page
const useItem = id => useQuery(["item", id], () => api.fetchItem(id)); // used by details page
const useUpdateItem = () => {
  const queryClient = useQueryClient();
  return useMutation(item => api.updateItem(item), {
    onSuccess: ({id}) => {
     queryClient.invalidateQueries(["item"]);
     queryClient.invalidateQueries(["item", id]);
   }
  });
};

UpdatePage 组件有一个表单组件,它采用默认值并将其加载到它的本地“草稿”状态 - 所以在这方面它有点“不受控制”,我不提升草稿状态。

// UpdatePage

const query = useItem(id);
const mutation = useUpdateItem();

return (
  {query.isSuccess && 
   !query.isLoading && 
   <ItemForm defaultValue={query.data} onSubmit={mutation.mutate} />
  }
);

问题是在我更新后,转到主页,然后返回详细信息页面,“defaultValue”在查询完成之前获取旧项目。我确实看到它达到了网络中的 API 并且新值又回来了,但为时已晚。如何在重新查询数据后只显示 ItemForm?或者有更好的模式吗?

isLoading 仅当查询处于没有数据的硬加载状态时才为真。否则,它会在后台重新获取时为您提供陈旧数据。这是针对大多数情况的目的(在重新验证时失效)。在详细视图卸载后,您的数据会在缓存中保留 5 分钟,因为这是默认的缓存时间。

最简单的解决方法就是将其设置为 0,这样您就不会保留该数据。

您也可以对 isFetching 标志作出反应,但是当请求发出时,这个标志将始终为真,例如 window 焦点重新获取也是如此。

旁注:默认情况下 invalidateQueries 是模糊的,因此这会使列表和详细视图都无效: queryClient.invalidateQueries(["item"])

我的 updateItem API 函数 returns 来自服务器的单个更新项目。

我用 setQueryData 解决了这个问题。

const useUpdateItem = () => {
  const queryClient = useQueryClient();
  // Note - api.updateItem is return the single updated item from the server
  return useMutation(item => api.updateItem(item), {
    onSuccess: data => {
     const { id } = data;
     // set the single item query
     queryClient.setQueryData('item', id], data);
     // set the item, in the all items query
     queryClient.setQueryData(
          ['item'],
          // loop through old. if this item replace, otherwise, don't
          old => {
            return old && old.map(d => (d.id === id ? data : d));
          }
        );
   }
  });
};

我会说,react-query 对键很挑剔,即使它是模糊的。最初我的 id 来自 url 搜索参数和一个字符串,但是从 db 返回的项目是一个 int,所以它不匹配。所以有点问题。

此外,当我返回主列表页面时,我看到项目发生了变化,这对来自 redux 的我来说有点奇怪。我本以为它在我触发同步 setQueryData 后立即发生了变化。因为我正在使用 react-router,所以“页面”已完全重新安装,所以不确定为什么它会加载旧查询数据然后更改它。

我今天遇到了同样的问题。扫描您的代码后,它可能是同样的问题。

const useItem = id => useQuery(["item", id], () => api.fetchItem(id)); // used by details page

查询的名称应该是唯一的。但根据您的详细信息,ID 更改取决于项目。通过这种方式,您可以使用不同的 ID 调用查询“项目”。如果您完成了第一个请求,您将获得缓存数据。

我的解决方案是这样写查询名称:

[`item-${id}`...]