如何在React可复用输入组件中实现react-hook-form 6的表单验证
解决react-hook-form 6结合自定义Input组件的表单验证问题
看起来你遇到的核心问题是自定义受控Input组件没有和react-hook-form的状态系统正确绑定,导致register的验证规则无法生效,同时表单状态也不同步。下面我会帮你一步步修复这个问题:
问题根源
你的InputField是一个受控组件(依赖外部传入的value和onChange),但存在两个关键问题:
- 没有把
inputRef传递给内部的真实<input>元素,react-hook-form无法获取DOM节点来注册表单控件 - 外部维护的
userInfo状态和react-hook-form的表单状态完全脱节,导致验证逻辑无法触发
解决方案1:将InputField改为非受控组件(推荐,符合react-hook-form设计理念)
react-hook-form的核心优势就是减少不必要的状态维护,所以我们可以把InputField改成非受控,让react-hook-form直接管理表单状态:
修改components/InputField.js
// 移除受控相关的value和onChange props,接收inputRef及其他需要的属性 const InputField = ({ label, name, placeholder, type, inputRef, ...rest }) => ( <div className='form-group w-full'> {label && <label htmlFor={name}>{label}</label>} {/* htmlFor与input的name对应,提升可访问性 */} {/* 将inputRef传递给真实input,同时展开register返回的其他属性 */} <input type={type} name={name} className='bg-customBlack-light w-full text-xs p-4 mb-6 rounded-md outline-none transition duration-150 ease-in-out' placeholder={placeholder} ref={inputRef} {...rest} /> </div> );
修改login.js
// 移除自己维护的userInfo状态和handleChange,直接用react-hook-form的能力 const { register, handleSubmit, errors } = useForm({ mode: 'onSubmit', reValidateMode: 'onClick', defaultValues: { username: '', password: '', } }); // 提交函数直接获取react-hook-form收集的表单数据 const onSubmit = (formData) => { console.log('登录数据:', formData); // {username: 'xxx', password: 'xxx'} // 这里编写登录逻辑 }; return ( <form noValidate onSubmit={handleSubmit(onSubmit)} > <InputField type='text' placeholder='Email or Username' name='username' // 直接把register的结果传递给组件,包含验证规则和绑定逻辑 {...register({ required: '请输入用户名或邮箱', // 可选:添加邮箱格式验证 pattern: { value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, message: '请输入有效的邮箱地址' } })} /> {errors.username && ( <span className='text-red-900'>{errors.username.message}</span> )} {/* 密码字段同理 */} <InputField type='password' placeholder='Password' name='password' {...register({ required: '请输入密码', minLength: { value: 6, message: '密码长度不能少于6位' } })} /> {errors.password && ( <span className='text-red-900'>{errors.password.message}</span> )} <Button type='submit' caption='Sign In' /> </form> );
解决方案2:使用Controller组件适配受控InputField(如果必须保留受控逻辑)
如果你因为业务需求必须让InputField保持受控状态,可以用react-hook-form提供的Controller组件来包装它,实现状态联动:
修改login.js
import { useForm, Controller } from 'react-hook-form'; // 记得导入Controller const { control, handleSubmit, errors } = useForm({ mode: 'onSubmit', reValidateMode: 'onClick', defaultValues: { username: '', password: '', } }); const onSubmit = (formData) => { console.log('登录数据:', formData); }; return ( <form noValidate onSubmit={handleSubmit(onSubmit)} > {/* 用Controller包装自定义受控组件 */} <Controller name="username" control={control} rules={{ required: '请输入用户名或邮箱', pattern: { value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, message: '请输入有效的邮箱地址' } }} render={({ field: { onChange, value, name } }) => ( <InputField type='text' placeholder='Email or Username' name={name} value={value} onChange={onChange} /> )} /> {errors.username && ( <span className='text-red-900'>{errors.username.message}</span> )} {/* 密码字段同理 */} <Controller name="password" control={control} rules={{ required: '请输入密码', minLength: { value: 6, message: '密码长度不能少于6位' } }} render={({ field: { onChange, value, name } }) => ( <InputField type='password' placeholder='Password' name={name} value={value} onChange={onChange} /> )} /> {errors.password && ( <span className='text-red-900'>{errors.password.message}</span> )} <Button type='submit' caption='Sign In' /> </form> );
注意事项
- 方案2不需要修改InputField组件,保持原有的受控逻辑即可
- 方案1更符合react-hook-form的性能优化理念,避免了不必要的状态重渲染
内容的提问来源于stack exchange,提问作者rjc30
相关产品推荐
相关产品推荐

