如何在TanStack Query中让依赖initialData的useQuery缓存失效更新?
问题
使用TanStack Query(原React Query)时,useQuery的initialData依赖useInfiniteQuery返回的数据,但在失效useInfiniteQuery缓存后,useQuery的缓存始终保持不变。业务需求需要让initialData强制接收依赖的新数据,代码实现如下:
帖子列表组件
const queryClient = useQueryClient(); const { data } = useInfiniteQuery({ queryKey: ['posts'], ... }); const flatten = useMemo(() => data && data.pages.map((page) => page).flat(), [data]); return ( <> {flatten.map(post => ( <Post key={post.id} item={post} /> ))} {/* 失效useInfiniteQuery缓存以获取新缓存数据 */} <button onClick={() => queryClient.invalidateQueries({ queryKey: ['posts'] })}> 失效帖子缓存 </button> </> )
帖子组件
function Post ({ item }) { const { data } = useQuery({ queryKey: ['post', item.id], queryFn: getPost, enabled: !!item.id, initialData: item }); // 尽管item的值已更新,但始终获取旧缓存数据 return <pre>{JSON.stringify(data)}</pre>; }
解决方案
问题核心是useQuery通过initialData初始化缓存后,后续即使依赖的item更新,它会优先读取已有的缓存数据,不会自动用新的initialData覆盖。可以通过以下方式解决:
1. 监听item变化,主动更新缓存
在Post组件中用useEffect监听item的变化,当item更新时,直接调用queryClient.setQueryData同步更新对应post的缓存:
function Post ({ item }) { const queryClient = useQueryClient(); const { data } = useQuery({ queryKey: ['post', item.id], queryFn: getPost, enabled: !!item.id, initialData: item }); useEffect(() => { // 当item更新时,强制覆盖缓存数据 queryClient.setQueryData(['post', item.id], item); }, [item, queryClient]); return <pre>{JSON.stringify(data)}</pre>; }
这种方式能保证useQuery的缓存和useInfiniteQuery返回的最新item完全同步,无需触发额外接口请求。
2. 开启refetchOnMount强制校验数据
如果希望每次组件重新渲染时都校验并获取最新数据,可以开启refetchOnMount: true,此时useQuery会重新执行queryFn,同时新的initialData会作为临时展示数据:
function Post ({ item }) { const { data } = useQuery({ queryKey: ['post', item.id], queryFn: getPost, enabled: !!item.id, initialData: item, refetchOnMount: true }); return <pre>{JSON.stringify(data)}</pre>; }
注意这种方式会触发实际的接口请求,适合需要确保数据和后端完全一致的场景。
3. 批量失效post缓存
在点击失效按钮时,除了失效posts的缓存,同时遍历所有post的缓存键进行失效:
<button onClick={() => { queryClient.invalidateQueries({ queryKey: ['posts'] }); // 遍历所有帖子,逐个失效对应缓存 flatten.forEach(post => { queryClient.invalidateQueries({ queryKey: ['post', post.id] }); }); }}> 失效帖子缓存 </button>
这样useInfiniteQuery更新后,每个Post组件的useQuery会重新初始化,新的initialData会生效。
内容的提问来源于stack exchange,提问作者Epple
相关产品推荐
相关产品推荐

