如何使用react-hook-form为表单输入项添加状态并实现数据更新存储
问题原因分析
- 事件处理函数逻辑错误:你当前写的
handleNorthDistanceValue直接把原状态值重新赋值给状态,没有读取输入框最新值,自然不会触发状态更新 - FormField组件未支持受控模式:输入框使用了
defaultValue(非受控组件属性),没有绑定value属性到传入的props,同时没有透传父组件传入的onChange事件到内部input - 钩子使用违规:你之前注释的代码里把
useEffect写在了事件处理函数内部,违反了React钩子只能在组件顶层调用的规则 - React Hook Form与自定义状态冲突:
register方法已经默认接管了表单值的管理,你要同时维护自定义状态需要同步两者的更新逻辑
修复步骤
1. 首先修改FormField组件,支持受控模式和自定义onChange
先更新FormFieldProps类型,添加onChange属性:
export type FormFieldProps = { // 原有属性不变 /** * 输入值变化时的回调函数 */ onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void }
然后修改FormField组件内部input的渲染逻辑:
const FormField: FunctionComponent<FormFieldProps> = (props) => { const { // 原有解构不变 onChange, } = props // 先处理register返回的属性 const reg = register(`${name}`, { ...rules, }) // 合并onChange事件,同时触发RHF的更新和自定义回调 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { reg.onChange(e) onChange?.(e) } const form_field = ( <div className={['form__field', className].join(' ')}> {label && <FormLabel text={label} forID={name} />} <input id={name} className={`form__input ${readonly ? 'form__path' : ''}`} placeholder={placeholder as string} // 受控模式用value绑定,不要用defaultValue value={value ?? defaultValue} required={required} type={type} disabled={disabled} readOnly={readonly} step={step} // 展开reg其他属性,替换自定义onChange {...reg} onChange={handleInputChange} /> </div> ) // 剩余逻辑不变 }
2. 修复父组件的状态更新逻辑
删除错误的事件处理函数,替换为读取输入值的逻辑:
const PlanDistanceFieldset: FunctionComponent<PlanDistanceFieldsetProps> = ( props ) => { const {register} = props const [showTip, setShowTip] = useState<boolean>(false) const [northDistance, setNorthDistanceValue] = useState(800) const [eastDistance, setEastDistanceValue] = useState(defaultDistancePlan.distanceEastValue) // 正确的更新逻辑,读取输入框最新值转成数字更新状态 const handleNorthDistanceChange = (e: React.ChangeEvent<HTMLInputElement>) => { setNorthDistanceValue(Number(e.target.value)) } const handleEastDistanceChange = (e: React.ChangeEvent<HTMLInputElement>) => { setEastDistanceValue(Number(e.target.value)) } // 调试用的useEffect要写在组件顶层 useEffect(() => { console.log('north', northDistance) }, [northDistance]); useEffect(() => { console.log('east', eastDistance) }, [eastDistance]); return ( <> <div className={'form__parameter_row_wrapper'}> <div className={'form__parameter_field'}> <FormLabel text={'Plan Distance [m]'} /> </div> <FormField label={'North-South Distance'} type={'number'} name={'north_south_distance'} value={northDistance} onChange={handleNorthDistanceChange} required={true} register={register} /> <FormField label={'East-West Distance'} type={'number'} name={'east_west_distance'} value={eastDistance} onChange={handleEastDistanceChange} required={true} register={register} /> <ToolTip onClick={() => { setShowTip(true) }} /> </div> </> ) }
补充说明
如果你不需要独立维护这两个值的状态,完全可以直接用React Hook Form内置的方法获取值,不用自己写useState:
- 用
useWatch('north_south_distance')可以实时获取输入框的值 - 用
setValue方法可以手动修改表单值
内容的提问来源于stack exchange,提问作者blahhh
相关产品推荐
相关产品推荐

