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

使用React-Query useMutation与react-hook-form提交数据时遇无限循环错误

解决React Hook Form + React Query useMutation无限重渲染问题

问题根源

你遇到的无限重渲染循环,核心原因是**useMutation的配置对象每次渲染都会生成新实例**,加上reset()触发的组件重渲染,形成了循环:

  1. 组件调用useCreateTag时,每次都会创建新的mutationFn和onSuccess函数,导致useMutation重新初始化,返回新的mutation对象。
  2. mutate引用变化后,依赖mutate的onSubmit(通过useCallback)会重新创建。
  3. 表单的onSubmit属性更新,触发组件重渲染,回到第一步循环。
  4. 当mutation成功调用reset()后,表单状态变化进一步触发重渲染,彻底激活这个循环。

另外,如果reset函数的引用不稳定(比如useForm的配置依赖了每次渲染都变化的值),会加剧这个问题。

解决方案

方案一:缓存useMutation的配置对象

在useCreateTag中用useMemo包裹useMutation的配置,确保只有依赖变化时才重新生成配置:

import { useMemo } from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';
import { Routes } from '../your-routes-path';
import { Tag } from '../your-tag-type-path';

const createTag = async (values: Tag, tenantId: string) => {
  const body = {
    ...values,
    tenantId,
  };
  const { data } = await axios.post(Routes.API.TAGS, body);
  return data;
};

export const useCreateTag = (tenantId: string, reset: () => void) => {
  const queryClient = useQueryClient();

  const mutationConfig = useMemo(() => ({
    mutationFn: (values: Tag) => createTag(values, tenantId),
    onSuccess: () => {
      successToast('Tag created');
      reset();
      queryClient.invalidateQueries({
        queryKey: ['tags', tenantId],
      });
    },
  }), [tenantId, reset, queryClient]);

  const mutation = useMutation(mutationConfig);
  return mutation;
};

方案二:将reset逻辑移到组件内部

把reset和提示框逻辑从自定义钩子中移除,放在组件的mutate调用参数里,减少钩子的依赖:

// 组件代码
const { register, handleSubmit, reset } = useForm();

const { mutate, isLoading, isError, error } = useCreateTag(tenantId);

const onSubmit: SubmitHandler<Tag> = useCallback(
  (values: Tag) => {
    mutate(values, {
      onSuccess: () => {
        successToast('Tag created');
        reset();
      },
    });
  },
  [mutate, reset],
);

// 自定义钩子代码
export const useCreateTag = (tenantId: string) => {
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: (values: Tag) => createTag(values, tenantId),
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: ['tags', tenantId],
      });
    },
  });
  return mutation;
};

方案三:确保reset函数引用稳定

如果reset的引用不稳定,检查useForm的配置,用useMemo缓存defaultValues等依赖项:

const defaultValues = useMemo(() => ({
  // 你的表单默认值,依赖props的话在这里处理
}), [props.yourDependency]);

const { register, handleSubmit, reset } = useForm({ defaultValues });

这些方案都能打破无限重渲染的循环,推荐优先尝试方案一或方案二,根据你的代码结构选择最合适的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:09:53