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

React Hook Form提交返回空对象、watch无返回值问题排查

问题根因
  • 你在代码中创建了两个完全独立的React Hook Form(以下简称RHF)实例,两套实例的数据流完全隔离,导致数据无法同步:
    1. FormWrapper 组件内部调用useForm()生成了第一个实例,提交逻辑handleSubmit绑定的是这个实例
    2. App 组件内部调用useForm()生成了第二个实例,输入框绑定的control属于这个实例
  • 两个实例没有关联,自然输入的内容无法同步到提交用的实例,所以watch和提交都只能拿到空对象。而AntD原生表单可以正常取值,是因为走的是AntD Form自己的数据流,和你写的RHF逻辑没有关联。
修复方案

两种常用改造方式,选一种即可:

方案1:统一在父组件创建RHF实例,传递给封装的FormWrapper

把RHF的实例创建逻辑放到外层,封装的FormWrapper只做 UI 层封装,不维护独立的RHF实例:

// 改造FormWrapper,从props接收提交相关参数
export const FormWrapper = ({ children, handleSubmit, onSubmit }) => {
  return <Form onFinish={handleSubmit(onSubmit)}>{children}</Form>;
};

// App组件统一管理RHF实例
export default function App() {
  const { control, watch, handleSubmit } = useForm();
  // 输入后可以正常打印对应字段值
  console.log(watch());

  const onSubmit = (data) => {
    // 提交时可以正常拿到 {tmp: 输入内容}
    console.log(data);
  };

  return (
    <FormWrapper handleSubmit={handleSubmit} onSubmit={onSubmit}>
      <FormItemWrapper>
        <Controller
          control={control}
          name="tmp"
          render={({ field }) => <Input {...field} />}
        />
      </FormItemWrapper>
      <FormItemWrapper>
        <Button htmlType="submit">Save</Button>
      </FormItemWrapper>
    </FormWrapper>
  );
}

方案2:FormWrapper内用FormProvider透传RHF实例,子组件从上下文取实例

如果希望FormWrapper做全封装,外层不用感知RHF的存在,可以用RHF自带的FormProvider透传实例:

// 改造FormWrapper,内置RHF实例并通过FormProvider透传
import { FormProvider, useForm } from 'react-hook-form';

export const FormWrapper = ({ children }) => {
  const methods = useForm();
  const onSubmit = (data) => {
    console.log(data);
  };
  return (
    <FormProvider {...methods}>
      <Form onFinish={methods.handleSubmit(onSubmit)}>{children}</Form>
    </FormProvider>
  );
};

// App组件从RHF上下文取实例,不需要单独调用useForm
import { useFormContext, Controller } from 'react-hook-form';

export default function App() {
  const { control, watch } = useFormContext();
  console.log(watch());
  return (
    <FormWrapper>
      <FormItemWrapper>
        <Controller
          control={control}
          name="tmp"
          render={({ field }) => <Input {...field} />}
        />
      </FormItemWrapper>
      <FormItemWrapper>
        <Button htmlType="submit">Save</Button>
      </FormItemWrapper>
    </FormWrapper>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 20:06:02