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

React Hook Form中handleSubmit未触发问题求助

React Hook Form handleSubmit 未触发问题的解决方案

问题场景

使用React Hook Form的useForm钩子时,点击模态框中的Ok提交按钮无任何反应,handleSubmit函数未被调用,但取消按钮的handleClose功能正常。相关代码如下:

useForm 初始化代码

const {
  register,
  handleSubmit,
  formState: { errors },
  watch,
  reset,  
} = useForm<SellingInvoiceClientDetails>({
  resolver: yupResolver(SellingInvoiceScheme),
  defaultValues: {
    rib: "",
    cardNumber: "",
    cardType: CardType.IDENTITY_CARD,
  },
});

提交处理函数

const addSellingInvoiceClientDetails = (
  sellingInvoiceDetails: SellingInvoiceClientDetails
) => {
  console.log(sellingInvoiceDetails.cardType);
  props.setSelectedClient();
  props.updateSellingInvoiceInfo(
    sellingInvoiceDetails.cardType,
    sellingInvoiceDetails.cardNumber,
    sellingInvoiceDetails.rib
  );
  handleClose();  
};

模态框与表单代码

return (
  <>
    <Modal.Header closeButton>
      <Modal.Title>
        <FormattedMessage id="client.info" />
      </Modal.Title>
    </Modal.Header>
    <Modal.Body>
      <Form onSubmit={handleSubmit(addSellingInvoiceClientDetails)}>
        <Form.Group className="mb-3">
          <Form.Label>
            <FormattedMessage id="card.number" />
          </Form.Label>
          <Form.Control
            {...register("cardNumber")}
            placeholder={intl.formatMessage({ id: "card.number" })}
          />
          <Form.Text className=" text-danger">
            {errors.cardNumber?.message}
          </Form.Text>
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>
            <FormattedMessage id="card.type" />
          </Form.Label>
          <Form.Check
            {...register("cardType")}
            type="radio"
            label={intl.formatMessage({ id: CardType.IDENTITY_CARD })}
            value={CardType.IDENTITY_CARD}
            id="identity_card"
          />
          <Form.Check
            {...register("cardType")}
            type="radio"
            label={intl.formatMessage({ id: CardType.DRIVING_LICENCE })}
            value={CardType.DRIVING_LICENCE}
            id="driving_licence"
          />
          <Form.Text className=" text-danger">
            {errors.cardType?.message}
          </Form.Text>
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>RIP</Form.Label>
          <input
            type="text"
            className="form-control"
            {...register("rib")}
            placeholder="XXXXXXXXXXXXX"
          />
          <Form.Text className=" text-danger">
            {errors.rib?.message}
          </Form.Text>
        </Form.Group>
      </Form>
    </Modal.Body>
    <Modal.Footer>
      <Button variant="secondary" onClick={handleClose}>
        <FormattedMessage id="cancel" />
      </Button>

      <Button
        type="submit"
        variant="primary"
        onClick={handleSubmit(addSellingInvoiceClientDetails)}
      >
        <FormattedMessage id="ok" />
      </Button>
    </Modal.Footer>
  </>
);

问题原因

  1. 提交按钮不在表单内部:Ok按钮位于<Form>标签之外的<Modal.Footer>中,此时按钮的type="submit"无法触发表单的onSubmit事件。
  2. onClick 调用方式错误:直接在onClick中执行handleSubmit(addSellingInvoiceClientDetails)会导致组件渲染时就调用该函数,而非点击按钮时触发,且这种方式无法正确触发表单校验流程。

解决方案

方案一:将提交按钮移至表单内部

把Ok按钮放到<Form>标签里,利用表单的onSubmit事件触发handleSubmit,这是React Hook Form的标准用法:

return (
  <>
    <Modal.Header closeButton>
      <Modal.Title>
        <FormattedMessage id="client.info" />
      </Modal.Title>
    </Modal.Header>
    <Modal.Body>
      <Form onSubmit={handleSubmit(addSellingInvoiceClientDetails)}>
        {/* 原有表单字段 */}
        <Form.Group className="mb-3">
          <Form.Label>
            <FormattedMessage id="card.number" />
          </Form.Label>
          <Form.Control
            {...register("cardNumber")}
            placeholder={intl.formatMessage({ id: "card.number" })}
          />
          <Form.Text className=" text-danger">
            {errors.cardNumber?.message}
          </Form.Text>
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>
            <FormattedMessage id="card.type" />
          </Form.Label>
          <Form.Check
            {...register("cardType")}
            type="radio"
            label={intl.formatMessage({ id: CardType.IDENTITY_CARD })}
            value={CardType.IDENTITY_CARD}
            id="identity_card"
          />
          <Form.Check
            {...register("cardType")}
            type="radio"
            label={intl.formatMessage({ id: CardType.DRIVING_LICENCE })}
            value={CardType.DRIVING_LICENCE}
            id="driving_licence"
          />
          <Form.Text className=" text-danger">
            {errors.cardType?.message}
          </Form.Text>
        </Form.Group>
        <Form.Group className="mb-3">
          <Form.Label>RIP</Form.Label>
          <input
            type="text"
            className="form-control"
            {...register("rib")}
            placeholder="XXXXXXXXXXXXX"
          />
          <Form.Text className=" text-danger">
            {errors.rib?.message}
          </Form.Text>
        </Form.Group>
        
        {/* 将提交按钮移到表单内部 */}
        <div className="d-flex justify-content-end gap-2">
          <Button variant="secondary" onClick={handleClose}>
            <FormattedMessage id="cancel" />
          </Button>
          <Button type="submit" variant="primary">
            <FormattedMessage id="ok" />
          </Button>
        </div>
      </Form>
    </Modal.Body>
    <Modal.Footer>
      {/* 移除原有按钮 */}
    </Modal.Footer>
  </>
);

方案二:保留按钮在Modal.Footer,手动触发表单提交

如果需要按钮留在模态框底部,可以通过给表单添加ref,手动调用submit()方法:

  1. 给表单添加ref:
import { useRef } from 'react';

// ...
const formRef = useRef<HTMLFormElement>(null);
  1. 修改表单和按钮代码:
return (
  <>
    <Modal.Header closeButton>
      <Modal.Title>
        <FormattedMessage id="client.info" />
      </Modal.Title>
    </Modal.Header>
    <Modal.Body>
      <Form 
        ref={formRef}
        onSubmit={handleSubmit(addSellingInvoiceClientDetails)}
      >
        {/* 原有表单字段 */}
      </Form>
    </Modal.Body>
    <Modal.Footer>
      <Button variant="secondary" onClick={handleClose}>
        <FormattedMessage id="cancel" />
      </Button>
      <Button
        variant="primary"
        onClick={() => formRef.current?.submit()}
      >
        <FormattedMessage id="ok" />
      </Button>
    </Modal.Footer>
  </>
);

额外注意点

  • 确保Yup校验规则没有阻止提交:检查SellingInvoiceScheme是否有必填字段未满足,比如cardNumber是否被标记为必填但用户未输入,这种情况下handleSubmit的成功回调不会执行,可通过errors对象查看校验失败信息。
  • 避免直接在onClick中执行handleSubmit,正确的方式是传递函数:onClick={() => handleSubmit(addSellingInvoiceClientDetails)()}(但这种方式会跳过表单的默认提交事件,优先使用前两种方案)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 05:01:08