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

如何在React可复用输入组件中实现react-hook-form 6的表单验证

解决react-hook-form 6结合自定义Input组件的表单验证问题

看起来你遇到的核心问题是自定义受控Input组件没有和react-hook-form的状态系统正确绑定,导致register的验证规则无法生效,同时表单状态也不同步。下面我会帮你一步步修复这个问题:

问题根源

你的InputField是一个受控组件(依赖外部传入的value和onChange),但存在两个关键问题:

  1. 没有把inputRef传递给内部的真实<input>元素,react-hook-form无法获取DOM节点来注册表单控件
  2. 外部维护的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:17:35