React useForm自定义组件获取输入值为undefined问题求助
React Hook Form 自定义Input组件提交值为undefined的解决方法
问题分析
你的自定义Input组件在表单提交后返回undefined,核心原因有三点:
- 未设置
name属性:react-hook-form完全依赖字段的name来收集和识别表单值,缺少该属性会导致无法匹配对应字段。 - 组件参数错误:Input组件的第二个参数
{register, errors}无法获取到值,React组件的props统一通过第一个参数传入,你需要从props中提取register。 - 受控组件干扰跟踪:你自己用
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
相关产品推荐
相关产品推荐

