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> </> );
问题原因
- 提交按钮不在表单内部:Ok按钮位于
<Form>标签之外的<Modal.Footer>中,此时按钮的type="submit"无法触发表单的onSubmit事件。 - 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()方法:
- 给表单添加ref:
import { useRef } from 'react'; // ... const formRef = useRef<HTMLFormElement>(null);
- 修改表单和按钮代码:
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
相关产品推荐
相关产品推荐

