Apollo-client中useLazyQuery调用refetch时偶尔返回undefined问题排查
问题原因
- 首次调用
refetch前未触发过lazyQuery的执行函数:useLazyQuery返回的refetch方法仅在你至少调用过一次触发函数(也就是你代码里的getById)后才会被正确初始化,未执行过getById就调用refetch的话,refetch本身就是undefined,await undefined自然不会有返回值。 - 未捕获异常导致逻辑中断:你的
refetch调用没有被try/catch包裹,当出现网络中断、参数错误等异常时,refetch会直接抛出错误中断执行,不会返回任何值,你拿到的结果就是undefined。 - 组件生命周期问题:如果
refetch还在pending状态时父组件Homescreen卸载、或者子组件Viewer卸载,pending的请求resolve后会返回空值。 - 部分旧版本Apollo Client存在已知bug:缓存命中且未指定强制走网络的fetchPolicy时,
refetch偶尔会出现返回值为空的问题。
解决方案
- 增加前置校验和异常捕获,避免空调用和未捕获错误:
const refetchObjects= async () => { // 先校验refetch是否存在 if (!refetch) return try { const res = await refetch(); // 校验返回值是否存在 if (!res) return const { error, data } = res if (error) { console.log(error); return } if (data) { // 注意:如果activeObject是普通变量而非useState/useRef存储的值,更新后不会触发组件重渲染 activeObject = data.getRegionById; } } catch (e) { console.log('refetch执行失败', e) } }
- 优先用触发函数
getById替代refetch,稳定性更高:你可以直接把getById从父组件传给子组件,每次调用时传入查询id,无需等待首次执行就能调用:
// 子组件调用逻辑 const refetchObjects= async () => { try { const { error, data } = await getById({ variables: { id: 你的查询ID } }); if (error) { console.log(error);} if (data) { activeObject = data.getRegionById; } } catch (e) { console.log(e) } }
- 给lazyQuery配置强制走网络的请求策略,避免缓存异常:
const [getById, {loading, error, data, refetch}] = useLazyQuery(GET_BY_ID, { fetchPolicy: 'network-only', notifyOnNetworkStatusChange: true });
内容的提问来源于stack exchange,提问作者Andrew Ge
相关产品推荐
相关产品推荐

