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

React Hook Form select字段校验方法及选值提交报错解决

问题描述

使用React Hook Form开发表单时,select下拉框选择任意选项后,可以在自定义onChange回调中拿到选中值,但提交表单时始终触发必填校验错误。
实现代码如下:

<div className="form-group mb-3">
    <label>Country</label>
    <Controller
        control={control}
        name="country"
        render={({ 
            field: { onChange, onBlur, value, ref }
        }) => (
            <select
                className='form-control form-select'
                onChange={(e) => setCountry(e.target.value)}
                inputRef={register("country", { required: true })}
            >
                <option>Select Country</option>
                {
                    Country.getAllCountries().map((item) => <option value={item.isoCode} key={item.isoCode}>{item.name}</option>)
                }
            </select>
        )}
    />
    {errors.country && <span className="error-text">Country is required</span>}
</div>

报错截图:
报错截图

问题原因

核心问题是写法不符合React Hook Form的受控组件绑定规则,导致表单内部始终无法获取country字段的有效值,具体错误点:

  • 重复注册字段:Controller本身就是RHF提供的受控组件注册入口,又额外调用register("country")手动注册同名字段,两套状态同步逻辑直接冲突
  • 值没有同步到表单状态:select的onChange回调里只调用了本地状态的setCountry,没有调用Controller注入的field.onChange方法,RHF内部存储的country字段始终是初始空值
  • 缺失必要绑定:没有把Controller提供的value、ref、onBlur属性绑定到select元素上,RHF无法追踪组件的实时值和交互状态
  • 默认选项无空值标识:第一个提示选项没有设置value="",会导致值匹配逻辑异常
修复方案

删除重复的register调用,把校验规则移到Controller的rules属性中,全量绑定Controller提供的字段属性,在onChange里按需同步本地状态和RHF表单状态即可,修复后代码如下:

<div className="form-group mb-3">
    <label>Country</label>
    <Controller
        control={control}
        name="country"
        rules={{ required: true }} // 校验规则统一写在Controller配置里
        render={({ 
            field: { onChange, onBlur, value, ref }
        }) => (
            <select
                className='form-control form-select'
                onChange={(e) => {
                    const selectedValue = e.target.value;
                    // 不需要单独存本地状态的话,setCountry可以直接删掉
                    setCountry(selectedValue);
                    // 必须调用,把选中值同步给RHF内部状态
                    onChange(selectedValue);
                }}
                onBlur={onBlur}
                value={value || ""}
                ref={ref}
            >
                <option value="">Select Country</option>
                {
                    Country.getAllCountries().map((item) => <option value={item.isoCode} key={item.isoCode}>{item.name}</option>)
                }
            </select>
        )}
    />
    {errors.country && <span className="error-text">Country is required</span>}
</div>

简化写法:如果不需要维护country的本地状态,可以直接把Controller提供的onChange绑定给select,不需要写自定义包裹逻辑:onChange={onChange}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:24:16