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

React Query封装useUser后onSuccess/onError多次触发的解决办法

解决React Query中useUser Hook的onSuccess/onError多次触发问题

问题原因

每个调用useUser的组件实例都会独立注册一套onSuccess和onError回调,当查询完成(成功/失败)时,所有注册的回调都会被执行,所以会出现多次触发的情况。

解决方案

方案1:全局统一处理回调(推荐)

如果回调逻辑是全局唯一的(比如全局提示、全局状态更新),不要把回调写在useUser内部,而是通过QueryClient的订阅功能实现全局监听,确保只触发一次:

// 在全局根组件(如App.tsx)中添加
import { useQueryClient } from '@tanstack/react-query';
import { useEffect } from 'react';

function App() {
  const queryClient = useQueryClient();

  useEffect(() => {
    // 订阅userData查询的成功/失败事件
    const unsubscribe = queryClient.subscribeQueries({
      queryKey: ['userData'],
      onSuccess: () => {
        console.log('仅触发一次的成功回调');
      },
      onError: (error) => {
        console.log('仅触发一次的错误回调');
      }
    });

    // 组件卸载时取消订阅
    return unsubscribe;
  }, [queryClient]);

  // ...其他代码
}

同时修改useUser,移除内部的回调:

export const useUser = () => {
  return useQuery<User>(['userData'], () => API.fetchUserData(), {
    staleTime: Infinity
  })
}

方案2:控制回调触发的时机

如果需要保留useUser内部的回调,但只希望在数据或错误状态变化时触发,可以通过notifyOnChangeProps限制回调的触发条件,避免组件重渲染导致的重复执行:

export const useUser = () => {
  return useQuery<User>(['userData'], () => API.fetchUserData(), {
    staleTime: Infinity,
    // 仅当data或error发生变化时,才触发回调
    notifyOnChangeProps: ['data', 'error'],
    onSuccess: () => {
      console.log('仅在数据加载/更新时触发');
    },
    onError: (error) => {
      console.log('仅在请求出错时触发');
    }
  })
}

方案3:标记回调是否已执行

如果只需要回调执行一次(比如首次加载成功/失败后不再触发),可以用useRef来标记回调的执行状态:

import { useRef } from 'react';
import { useQuery } from '@tanstack/react-query';

export const useUser = () => {
  const hasRunSuccess = useRef(false);
  const hasRunError = useRef(false);

  return useQuery<User>(['userData'], () => API.fetchUserData(), {
    staleTime: Infinity,
    onSuccess: () => {
      if (!hasRunSuccess.current) {
        console.log('只触发一次的成功回调');
        hasRunSuccess.current = true;
      }
    },
    onError: (error) => {
      if (!hasRunError.current) {
        console.log('只触发一次的错误回调');
        hasRunError.current = true;
      }
    }
  })
}

内容的提问来源于stack exchange,提问作者React-beginner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 12:07:25