You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useQuery带variables用onError处理报错及重渲染问题如何解决?

问题根源

  1. 顶层直接通过queryColumns.error判断触发弹窗导致死循环的原因:handleErrorDialogOpen内部会调用setState修改组件状态,触发组件重渲染,只要error实例没有被清空,重渲染后会再次执行判断逻辑调用弹窗打开方法,进入无限循环最终崩溃。
  2. 第一个useQuery的回调不触发的常见原因:
    • handleErrorDialogOpen、国际化方法t未用useCallback包裹,每次渲染生成新的引用,导致useQuery的配置项每次都是新对象,要么触发重复请求,要么回调被重置
    • 两个请求并行触发时,后完成的请求的弹窗逻辑会覆盖前一个的弹窗状态,导致第一个请求的弹窗没有展示机会
    • React Query v4及以上版本中,内置的onError/onCompleted默认仅在请求首次完成/失败时触发,如果查询已有缓存数据,回调不会再次执行;v5版本已经将查询级别的onError/onCompleted标记为废弃。

最优解决方案(兼容所有版本,无引用问题)

不用依赖useQuery内置回调,通过useEffect监听请求状态触发弹窗,同时固定所有回调的引用避免重复执行:

// 首先固定弹窗方法的引用
const handleErrorDialogOpen = useCallback((msg) => {
  // 原有弹窗逻辑不变,建议此处增加错误队列,避免多个错误互相覆盖
  setErrorMsg(msg);
  setIsDialogOpen(true);
}, [/* 填入方法内部依赖的所有状态变量 */]);

// 国际化方法也固定引用,避免每次渲染生成新实例
const stableT = useCallback(t, []);

// useQuery仅保留基础配置,不写回调
const queryColumns = useQuery(web_list_query, {
  variables: {entity: "device", variant: 'std'},
});

const queryRows = useQuery(getDevices_query, {});

// 单独监听columns的请求状态
useEffect(() => {
  if (queryColumns.error) {
    handleErrorDialogOpen(stableT("There was an error retrieving rows data from 'web_list_query: device'"));
  }
  if (queryColumns.isSuccess) {
    handleErrorDialogOpen(stableT("Columns Groovy  baby Yeah"));
  }
// 依赖项仅传入状态和固定引用的方法,避免多余触发
}, [queryColumns.error, queryColumns.isSuccess, handleErrorDialogOpen, stableT]);

// 单独监听rows的请求状态
useEffect(() => {
  if (queryRows.error) {
    handleErrorDialogOpen(stableT("There was an error retrieving rows data from 'getDevices_query: device'"));
  }
  if (queryRows.isSuccess) {
    handleErrorDialogOpen(stableT("Groovy  baby "));
  }
}, [queryRows.error, queryRows.isSuccess, handleErrorDialogOpen, stableT]);

备选方案(仅适用于v3/v4版本)

如果要继续使用内置回调,只需固定配置项里所有方法的引用即可:

const stableHandleError = useCallback(handleErrorDialogOpen, [/* 依赖项 */]);
const stableT = useCallback(t, []);

const queryColumns = useQuery(web_list_query, {
  variables: {entity: "device", variant: 'std'},
  onError: () => {
    stableHandleError(stableT("There was an error retrieving rows data from 'web_list_query: device'"));
  },
  onCompleted: ()=> {
    stableHandleError(stableT("Columns Groovy  baby Yeah"));
  },
  // 增加缓存时间避免重复请求触发多次回调
  staleTime: 5 * 60 * 1000
});

const queryRows = useQuery(getDevices_query, {
  onError: () => {
    stableHandleError(stableT("There was an error retrieving rows data from 'getDevices_query: device'"));
  },
  onCompleted: ()=> {
    stableHandleError(stableT("Groovy  baby "));
  },
  staleTime: 5 * 60 * 1000
});

内容的提问来源于stack exchange,提问作者Neal Rogers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 21:15:01