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

React Hook Form onChange模式在自定义输入组件中失效问题求助

问题原因分析

你的onChange模式不生效,核心问题出在自定义组件FloatInput的实现逻辑上:你在input元素上同时展开register返回的属性,又单独设置了value和onChange参数,这会直接覆盖register自带的状态跟踪方法,导致React Hook Form无法实时感知输入值的变化,自然不会触发onChange模式下的校验逻辑。

修复方案

方案1:使用React Hook Form的Controller组件(推荐)

Controller是官方专门为自定义组件设计的绑定API,能完美解决受控自定义组件的表单状态同步问题。

第一步:修改FloatInput组件

让它遵循标准受控组件的props设计,不再接收register参数:

const FloatInput: FC<{
    label: string
    type?: React.HTMLInputTypeAttribute
    onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
    value: string
    required?: boolean
}> = ({
    label,
    type = 'text',
    onChange,
    value,
    required = false,
}) => {
    return (
        <div className={styles.wrapper}>
            <input
                required={required}
                value={value}
                onChange={onChange}
                className={styles.input}
                type={type}
                placeholder=' '
            />
            <label className={styles.label}>{label}</label>
        </div>
    )
}

第二步:在Login组件中用Controller包裹FloatInput

const Login = () => {
    const {
        handleSubmit,
        control, // 获取control对象
        formState: { errors },
        reset
    } = useForm<ILoginInput>({
        mode: 'onChange'
    })
    const onSubmit: SubmitHandler<ILoginInput> = data => {
        reset()
    }
    return (
        <div className={styles.wrapper}>
            <form
                onSubmit={handleSubmit(onSubmit)}
                className={styles.form}
                method='post'>
                <div>
                    <Controller
                        name="email"
                        control={control}
                        rules={{ required: 'Email is required' }}
                        render={({ field: { onChange, value } }) => (
                            <FloatInput
                                onChange={onChange}
                                value={value}
                                type='text'
                                label='Email'
                                required
                            />
                        )}
                    />
                    {errors?.email && <p>{errors.email.message}</p>}
                </div>
            </form>
        </div>
    )
}

方案2:调整自定义组件,避免覆盖register属性

如果不想使用Controller,可以修改FloatInput的props优先级,让register自带的value和onChange优先生效:

修改FloatInput组件

const FloatInput: FC<{
    label: string
    type?: React.HTMLInputTypeAttribute
    onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
    value?: string
    required?: boolean
    register: ReturnType<typeof useForm['register']>
}> = ({
    label,
    type = 'text',
    onChange,
    value,
    required = false,
    register
}) => {
    return (
        <div className={styles.wrapper}>
            <input
                {...register}
                // 仅当register未提供对应属性时,才使用自定义参数
                value={value ?? register.value}
                onChange={onChange ?? register.onChange}
                className={styles.input}
                type={type}
                placeholder=' '
                required={required}
            />
            <label className={styles.label}>{label}</label>
        </div>
    )
}

使用时注意事项

调用FloatInput时,不要手动传入value和onChange,完全依赖register提供的状态:

<FloatInput
    register={register('email', {
        required: 'Email is required',
    })}
    type='text'
    label='Email'
    required
/>

以上两种方案都能让React Hook Form实时跟踪输入变化,触发onChange模式下的校验逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:05:25