useLazyQuery的onCompleted回调在状态变更后未触发求助
问题分析与解决方案
核心问题原因
- 缓存策略限制了实时数据获取:使用
cache-and-network时,Apollo Client会优先返回缓存数据,若网络请求返回的新数据与缓存状态一致(或缓存未及时更新),onCompleted回调可能无法触发;即使数据已更新,也可能因缓存优先级导致回调拿到的仍是旧状态。 - 定时器引用存在闭包问题:全局变量
timer在组件重新渲染时容易出现引用失效,导致clearInterval无法正确停止定时器,造成查询持续执行。
修复步骤
1. 调整查询的缓存策略
将fetchPolicy改为'network-only',强制每次请求都从网络拉取最新数据,确保onCompleted能获取到实时的进度状态:
const [ checkProgress, { loading2, data2 } ] = useLazyQuery(CHECK_PROGRESS, { fetchPolicy: 'network-only', // 替换原cache-and-network策略 onCompleted: (data) => { if(data.progress.completed) { setInProgress(false) // 你的完成状态逻辑代码 } else { // 你的未完成状态逻辑代码 } } } )
2. 使用useRef管理定时器引用
用useRef替代全局变量存储定时器,避免闭包导致的引用丢失问题,确保定时器能被正确清理:
import { useRef } from 'react'; // 替换原全局timer变量 const timerRef = useRef(null); useEffect(() => { if (inProgress) { timerRef.current = setInterval(() => { checkProgress() }, 1000 * 60) } else { if(timerRef.current) { clearInterval(timerRef.current) timerRef.current = null } } // 组件卸载时强制清理定时器 return () => { if(timerRef.current) { clearInterval(timerRef.current) } } }, [inProgress, checkProgress]) // 添加checkProgress到依赖,避免闭包捕获旧函数引用
3. 兜底方案:监听查询结果变化(可选)
如果担心onCompleted仍有触发异常,可以通过监听data2的变化来处理状态更新,作为额外保障:
useEffect(() => { if(data2?.progress?.completed) { setInProgress(false) // 你的完成状态逻辑代码 } }, [data2])
修复后效果
当data.progress.completed变为true时:
onCompleted会触发并调用setInProgress(false)useEffect检测到inProgress状态变化,会立即清理定时器,停止后续的进度查询
内容的提问来源于stack exchange,提问作者Remy Wang
相关产品推荐
相关产品推荐

