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

使用mutateAsync链式调用React Query mutations触发无限循环求助

问题

尝试通过自定义hooks和mutateAsync链式调用两个mutations时,触发了React的过多重渲染错误,错误指向这两个mutations的调用。虽然数据已成功存入数据库,router.push也正常工作,但仍报错。

已知可行方案(但不想采用):将调用写在mutationFn中、在第一个mutation的onSuccess回调中调用第二个。希望保留mutateAsync以保持两个mutations分离。

调用代码

const {
    mutateAsync: mutateTenant,
    isError: tenantIsError,
    error: tenantError,
  } = useCreateTenant(router);
  const {
    data: customerId,
    mutateAsync: mutateCustomer,
    isSuccess,
    isError: customerIsError,
    error: customerError,
  } = useCreateCustomer();

  if (isSuccess) {
    setState({ ...state, customerId });
  }

  const onSubmit = async (values) => {
    await mutateCustomer(values);
    await mutateTenant(values);
  };

自定义hooks代码

export const useCreateCustomer = () => {
  const mutation = useMutation({
    mutationFn: (values) => createCustomer(values),
  });
  return mutation;
};

export const useCreateTenant = (router: NextRouter) => {
  const mutation = useMutation({
    mutationFn: (values) => createTenant(values),
    onSuccess: (data) => {
      successToast(data.message);
      router.push('/register/plan');
    },
  });
  return mutation;
};
解决方案

错误根源

问题出在这段直接在组件渲染流程中执行的state更新代码:

if (isSuccess) {
  setState({ ...state, customerId });
}

当useCreateCustomer的isSuccess变为true时,会立即调用setState触发组件重渲染。但React Query的isSuccess状态不会自动重置(除非触发新的mutation),导致每次重渲染时isSuccess仍为true,进而再次执行setState,形成无限重渲染循环,最终触发React的过多重渲染错误。

修复方案

方案1:用useEffect监听状态变化

把state更新逻辑放到useEffect中,仅在isSuccess和customerId变化时执行:

useEffect(() => {
  if (isSuccess && customerId) {
    setState(prev => ({ ...prev, customerId }));
  }
}, [isSuccess, customerId]);

这样只会在isSuccess从false变为true时执行一次state更新,不会触发循环。

方案2:mutation完成后手动重置状态

在useEffect中更新state后,调用React Query提供的reset方法重置mutation状态,避免后续重渲染时isSuccess仍为true:

const {
  data: customerId,
  mutateAsync: mutateCustomer,
  isSuccess,
  reset, // 解构出reset方法
  isError: customerIsError,
  error: customerError,
} = useCreateCustomer();

useEffect(() => {
  if (isSuccess && customerId) {
    setState(prev => ({ ...prev, customerId }));
    reset(); // 重置mutation状态
  }
}, [isSuccess, customerId, reset]);

方案3:React Query v5+ 禁用自动success状态

如果使用React Query v5及以上版本,可以在调用mutateAsync时传入{ success: false },禁止自动设置isSuccess状态,直接用返回的数据更新state:

const onSubmit = async (values) => {
  const customerData = await mutateCustomer(values, { success: false });
  setState(prev => ({ ...prev, customerId: customerData.id }));
  await mutateTenant(values);
};

这种方式完全不依赖isSuccess状态,从根源避免循环问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 07:46:17