TanStack useQuery重新获取后仍显示旧数据的问题排查
相关代码
查询组件代码
const activeFiles = useQuery({ queryKey: ["active_files", projectId], queryFn: () => getActiveFiles(projectId), enabled: true, refetchOnWindowFocus: false });
另一个组件的Mutation代码
const queryClient = useQueryClient(); return useMutation({ // 省略其他配置项 onSuccess: async() => { await queryClient.invalidateQueries({ queryKey: ["active_files", projectId] }); anotherFunction(); }, });
问题现象
onSuccess已正常执行,等待数秒后点击按钮读取activeFiles的值,发现activeFiles.data仍是旧数据,但activeFiles.isStale为true。已确认projectId完全一致,断点验证getActiveFiles确实执行并返回了新数据,anotherFunction也正常进入,但后续读取activeFiles仍得到旧数据。
尝试过的无效操作
- 在读取前添加
await activeFiles.refetch();,无效 - 确保
getActiveFiles返回全新数组(用[...results]包裹),无效 - 在
useQuery中添加staleTime: 0,无效 - 在
invalidateQueries中添加refetchType: "all",无效
目前仅通过await activeFiles.refetch().then((files)=>{......})能获取新数据,但这种方式会导致getActiveFiles重复执行,且不符合invalidateQueries自动触发数据更新的预期。
补充:activeFiles的访问场景
activeFiles在组件清理函数中被访问,代码如下:
async function handleExit() { // 此处之前无await操作 await possiblyDelayedFunction(activeFiles.data); } useEffect(() => { // 省略其他逻辑 return function cleanup() { handleExit(); }; }, []);
解决方案
问题根源在于闭包捕获的旧值:useEffect依赖项为空数组,导致handleExit在组件挂载时就被创建,它捕获的是当时的activeFiles.data(旧数据)。后续即使activeFiles因invalidateQueries更新,闭包里的activeFiles.data还是最初的旧值。
修复方案一:更新useEffect依赖项
将activeFiles.data加入依赖数组,让handleExit在数据更新时重新创建,从而捕获最新数据:
useEffect(() => { // 省略其他逻辑 async function handleExit() { await possiblyDelayedFunction(activeFiles.data); } return function cleanup() { handleExit(); }; }, [activeFiles.data]);
修复方案二:用useRef保存最新数据
如果不想频繁更新useEffect,可以用useRef实时同步最新的activeFiles.data,让清理函数能访问到最新值:
const activeFilesDataRef = useRef(activeFiles.data); useEffect(() => { activeFilesDataRef.current = activeFiles.data; }, [activeFiles.data]); async function handleExit() { await possiblyDelayedFunction(activeFilesDataRef.current); } useEffect(() => { // 省略其他逻辑 return function cleanup() { handleExit(); }; }, []);
invalidateQueries标记查询为过时后,React Query会在组件重新渲染时自动触发重取,但如果组件因闭包无法感知状态变化,就无法更新数据。上述两种方法都是让清理函数能访问到最新的查询数据。
内容的提问来源于stack exchange,提问作者jdm

