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

React useForm自定义组件获取输入值为undefined问题求助

React Hook Form 自定义Input组件提交值为undefined的解决方法

问题分析

你的自定义Input组件在表单提交后返回undefined,核心原因有三点:

  1. 未设置name属性:react-hook-form完全依赖字段的name来收集和识别表单值,缺少该属性会导致无法匹配对应字段。
  2. 组件参数错误:Input组件的第二个参数{register, errors}无法获取到值,React组件的props统一通过第一个参数传入,你需要从props中提取register。
  3. 受控组件干扰跟踪:你自己用useState维护了输入值,导致react-hook-form通过ref注册的字段无法同步跟踪值变化,违背了其非受控组件的设计逻辑。

解决方案

方案一:改用非受控组件(推荐,贴合react-hook-form设计)

去掉Input组件内部的state,完全由react-hook-form通过ref管理字段值。

修改后的Input.jsx

import React from 'react';
import './Input.scss';

export default function Input(props) {
    const { register, name, type = 'text', id, placeholder, maxLength = "", legend, showLength, nameChange } = props;

    const handleInput = (e) => {
        // 同步更新父组件需要的值
        nameChange?.(e.target.value);
    };

    // 计算剩余字符数
    const getRemainingLength = () => {
        if (!showLength || !maxLength) return null;
        const currentValue = register.current?.value || '';
        return maxLength - currentValue.length;
    };

    return (
        <div className="input-holder">
            <input
                ref={register}
                type={type}
                id={id}
                name={name} // 必须添加name属性
                placeholder={placeholder}
                onInput={handleInput}
                maxLength={maxLength}
            />
            {legend && <span className='legend'>{legend}</span>}
            {showLength && maxLength && <span className='legend'>{getRemainingLength()}</span>}
        </div>
    )
}

修改后的Form.jsx

import React from 'react';
import { useForm } from "react-hook-form";

import Button from './Button';
import Input from './Input';

export default function UserForm(props) {
    const { register, handleSubmit } = useForm();

    function submitForm(data) {
        console.log(data); // 现在能正确输出{name: 输入值, email: 输入值}
    }

    return (
        <div className="user-form">
            <form onSubmit={handleSubmit(submitForm)}>
                <Input
                    placeholder="Name"
                    name="name" // 唯一标识字段的name
                    nameChange={(name) => props.userName(name)}
                    showLength={true} // 改为布尔值,避免字符串歧义
                    maxLength={35}
                    legend="Remaining Char: "
                    id="name"
                    register={register({ required: true })} // 可添加验证规则
                />
                <Input
                    placeholder="E-mail"
                    type="email"
                    id="email"
                    name="email" // 唯一标识字段的name
                    register={register({ required: true, pattern: /^\S+@\S+$/i })}
                />

                <Button label="Buy" type="submit" /> {/* 确保按钮为submit类型 */}
            </form>
        </div>
    )
}

方案二:用Controller包裹受控组件(保留内部state的场景)

如果需要保留Input组件的受控状态(自己维护value),可以用react-hook-form的Controller组件来桥接,确保表单能跟踪值变化。

修改后的Input.jsx

import React from 'react';
import './Input.scss';

export default function Input(props) {
    const { value, onChange, type = 'text', id, placeholder, maxLength = "", legend, showLength, nameChange } = props;

    const handleInput = (e) => {
        onChange(e); // 同步到react-hook-form
        nameChange?.(e.target.value);
    };

    const remainingLength = maxLength - value.length;

    return (
        <div className="input-holder">
            <input
                type={type}
                id={id}
                placeholder={placeholder}
                value={value}
                onInput={handleInput}
                maxLength={maxLength}
            />
            {legend && <span className='legend'>{legend}</span>}
            {showLength && maxLength && <span className='legend'>{remainingLength}</span>}
        </div>
    )
}

修改后的Form.jsx

import React from 'react';
import { useForm, Controller } from "react-hook-form";

import Button from './Button';
import Input from './Input';

export default function UserForm(props) {
    const { control, handleSubmit } = useForm();

    function submitForm(data) {
        console.log(data);
    }

    return (
        <div className="user-form">
            <form onSubmit={handleSubmit(submitForm)}>
                <Controller
                    name="name"
                    control={control}
                    defaultValue=""
                    render={({ field }) => (
                        <Input
                            placeholder="Name"
                            nameChange={(name) => props.userName(name)}
                            showLength={true}
                            maxLength={35}
                            legend="Remaining Char: "
                            id="name"
                            {...field} // 传递value、onChange等核心属性
                        />
                    )}
                />
                <Controller
                    name="email"
                    control={control}
                    defaultValue=""
                    render={({ field }) => (
                        <Input
                            placeholder="E-mail"
                            type="email"
                            id="email"
                            {...field}
                        />
                    )}
                />

                <Button label="Buy" type="submit" />
            </form>
        </div>
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:20:51