react-hook-form v7如何实现表单校验、提交及错误提示?
react-hook-form v7 结合 react-bootstrap 表单问题解决方案
问题1:配置全量校验通过后再提交API
你不需要额外写onChange触发提交的逻辑,react-hook-form自带的handleSubmit方法默认就会先执行全量表单规则校验,只有所有字段校验全部通过时,才会执行你传入的提交回调函数,完全满足“校验通过才发API请求”的需求。
你考虑的onChange={handel(on submit)} onSubmit={handleOnSubmit}写法是错误的,会导致输入框值每次变化都触发提交逻辑,完全不符合正常表单交互逻辑。
Next.js环境下正确的提交配置参考:
// 从react-hook-form导入所需方法 import { useForm } from "react-hook-form"; export default function ContactForm() { // 初始化表单方法,可按需配置校验触发时机 const { register, handleSubmit, formState: { errors } } = useForm({ mode: 'onSubmit', // 默认值,点击提交按钮时才触发全量校验,需要输入时实时校验可改为'onChange' reValidateMode: 'onChange' }); // 提交逻辑:仅当全量校验全部通过时,该函数才会执行 const submitForm = async (formData) => { // 此处直接写API调用逻辑即可,formData为所有校验通过的字段值集合 const res = await fetch('/api/contact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }) // 后续接口响应处理逻辑自行补充 } return ( <form onSubmit={handleSubmit(submitForm)}> {/* 表单字段放置处 */} <button type="submit">提交</button> </form> ) }
注意:不要给输入框单独绑定自定义onChange覆盖register注入的逻辑,除非你明确知晓如何和RHF内部状态同步,否则会出现状态错乱问题。
问题2:错误提示无法正常渲染
你的代码存在3个核心错误,直接导致错误信息无法读取、渲染:
- 字段名不匹配:
register的第一个参数必须和ErrorMessage组件的name属性完全一致,你写的是register("Mobile number", {...}),但ErrorMessage读取的是name="phone",字段名不匹配的情况下,RHF无法将校验规则和对应字段绑定,自然读不到错误信息。 - 状态逻辑冲突:你给输入框同时绑定了
{...register()},又手动添加了value={phone} onChange={(e) => { setPhone(e.target.value) }},相当于同时使用RHF的非受控状态和自定义本地state,手动绑定的onChange会覆盖register注入的状态更新逻辑,导致RHF无法获取输入值、也无法触发校验状态更新。 - 组件适配问题:如果你使用的是react-bootstrap的表单控件,直接将适配原生DOM的register属性绑定在自定义组件上可能存在属性透传失败的问题,建议要么使用原生input标签,要么用RHF提供的
Controller组件包裹第三方UI组件。
修正后的手机号字段代码
import { Form } from 'react-bootstrap'; import { useForm } from 'react-hook-form'; // 注意ErrorMessage需要从@hookform/error-message导入 import { ErrorMessage } from '@hookform/error-message'; // 表单内手机号字段部分 <div className="m-t-15"> <Form.Control style={{width: "100%"}} type="tel" placeholder="Wpisz swój telefon" // register第一个参数和下方ErrorMessage的name保持一致,统一为phone {...register("phone", { required: { value: true, message: "Numer telefonu jest obowiązkowy, zebysmy mogli sie skontaktować" }, pattern: { value: /^[0-9+-]+$/, message: "Dozwolone sa wylacznie cyfry" }, minLength: { value: 9, message: "Numer telefonu jest za krótki" }, maxLength: { value: 15, message: "Numer telefonu jest za długi" } })} /> <ErrorMessage errors={errors} name="phone" render={({ messages }) => { return messages ? Object.entries(messages).map(([type, message]) => ( <p key={type} className="text-danger small mt-1">{message}</p> )) : null }} /> </div>
关键注意事项
- 删掉和表单字段重复的本地state声明,比如
const [phone, setPhone] = useState(''),RHF会自行管理表单值,不需要额外声明state存储。需要读取字段值时,用watch('phone')获取即可,提交时也可以直接从入参formData里拿到对应值。 - 如果确实需要在值变化时执行自定义逻辑(比如手机号格式化),可以把逻辑写在register的onChange配置项里,不要直接覆盖输入框的onChange属性:
{...register("phone", { // 其余校验规则保持不变 onChange: (e) => { // 此处写自定义逻辑即可,不需要手动setState同步值 console.log('当前输入值', e.target.value) } })} - 确保传入ErrorMessage的
errors对象是从useForm返回的formState中解构得到的,不要自行声明errors变量。
内容的提问来源于stack exchange,提问作者user19358070
相关产品推荐
相关产品推荐

