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

React Hook Form嵌套场景下如何实现第二个表单独立提交

问题根因

HTML 标准原生不支持 <form> 元素嵌套,内层表单触发提交时,事件会沿DOM树向上冒泡,直接触发外层绑定的submit回调,这和React Hook Form本身的逻辑无关,是DOM事件机制+非法标签嵌套导致的行为。
另外你代码里useForm的mode配置存在语法错误:mode接收字符串值,合法值为onSubmit/onBlur/onChange/onTouched/all,不需要包裹在对象里;同时Controller组件的校验规则不能直接写required属性,要传入rules配置项。

修复方案

优先选择第一种符合规范的写法,从根源避免兼容问题:

  • 方案1:移除嵌套form,改为平级结构(最推荐):把两个表单改为DOM层面的平级元素,完全符合HTML规范,布局层面可以用CSS调整视觉位置,实现和嵌套完全一致的展示效果。
  • 方案2:保留视觉嵌套,去掉内层form标签,手动绑定按钮事件阻止冒泡:如果业务布局必须把校验区块放在主表单的视觉区域内,不要给内层校验区块套<form>标签,直接给Check按钮绑定点击事件,触发内层表单提交逻辑的同时调用stopPropagation()阻止事件冒泡,就不会触发外层表单的提交。

注意:所有表单内的按钮如果不是用来触发当前表单提交的,都要显式加type="button",因为form内的button默认type是submit,会自动触发最近层级form的提交事件,这是表单提交异常的高频诱因。

修正后代码示例
// 修正useForm的mode配置错误
const { register, handleSubmit, errors, control } = useForm({
  mode: 'onBlur',
});

const {
  register: register2, handleSubmit: handleSubmit2, errors: errors2, control: control2,
} = useForm({
  mode: 'onBlur',
});

const onSubmit = (data) => {
  console.log('主表单提交', data);
};
const onSubmit2 = (data) => {
  console.log('内层校验提交', data);
};


// -------------- 方案1:平级表单写法(推荐) --------------
<div>
  <form onSubmit={handleSubmit(onSubmit)}>
    <Controller
      as={InputMask}
      control={control}
      mask="+\9\98 99 999 99 99"
      name="phone"
      id="phone"
      defaultValue={phone}
      rules={{ required: true }}
    />
    <button type="submit">Send</button>
  </form>

  {/* 内层校验表单和主表单平级,用CSS调整到目标视觉位置即可 */}
  <form onSubmit={handleSubmit2(onSubmit2)}>
    <Controller
      as={InputMask}
      control={control2}
      mask="+\9\98 99 999 99 99"
      name="phone_alif"
      id="phone_alif"
      rules={{ required: true }}
    />
    <button type="submit">Check</button>
  </form>
</div>


// -------------- 方案2:必须视觉嵌套时的写法 --------------
<form onSubmit={handleSubmit(onSubmit)}>
  <Controller
    as={InputMask}
    control={control}
    mask="+\9\98 99 999 99 99"
    name="phone"
    id="phone"
    defaultValue={phone}
    rules={{ required: true }}
  />

  {/* 内层不再套form标签 */}
  <div>
    <Controller
      as={InputMask}
      control={control2}
      mask="+\9\98 99 999 99 99"
      name="phone_alif"
      id="phone_alif"
      rules={{ required: true }}
    />
    <button 
      type="button"
      onClick={(e) => {
        e.stopPropagation();
        handleSubmit2(onSubmit2)();
      }}
    >
      Check
    </button>
  </div>
  
  <button type="submit">Send</button>
</form>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:21:18