【问题标题】:react-query getting old data反应查询获取旧数据
【发布时间】:2021-02-23 23:27:31
【问题描述】:

我有一个作为项目列表的母版页,以及一个用于获取和更新项目的详细信息页面。我有以下基于 react-query 库的钩子:

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 组件有一个表单组件,它接受一个 defaultValue 并将其加载到它的本地“草稿”状态 - 所以在这方面它有点“不受控制”,我不提升草稿状态。

// UpdatePage

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

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

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

【问题讨论】:

    标签: javascript reactjs react-query


    【解决方案1】:

    我的 updateItem API 函数从服务器返回单个更新的项目。

    我使用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,所以“页面”已完全重新安装,所以不确定为什么它会加载旧的查询数据然后更改它。

    【讨论】:

      【解决方案2】:

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

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

      您也可以对isFetching 标志做出反应,但是当请求发出时,此标志始终为真,例如,对于重新获取窗口焦点也是如此。

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

      【讨论】:

      • 我确实希望它缓存 5,除非更新。即使我使用 isFetching 我也没有潜在的比赛,它最初不是错误的吗?我需要一个“无效”或回到绘图板。感谢您对模糊无效的说明,我希望它像这样工作
      • 您可以将本地状态保持 5 分钟,并在更新后将其设置为 0(在 onSuccess 处理程序中)
      【解决方案3】:

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-09
        • 1970-01-01
        • 2020-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-10
        • 1970-01-01
        相关资源
        最近更新 更多