反应查询获取旧数据
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}`...]
我有一个包含项目列表的母版页,以及一个我可以在其中获取和更新项目的详细信息页面。我有以下基于反应查询库的挂钩:
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}`...]