React Hook Form复用组件报错:无法给函数组件传refs
解决React Hook Form复用输入组件的绑定问题
一、用forwardRef配合register的正确实现
提交值不更新的核心原因,大多是没把register返回的属性完整传递给原生输入框,或是forwardRef未正确关联到内部的原生input。
示例代码:
import { forwardRef } from 'react'; // 复用输入组件 const InputField = forwardRef(({ label, ...props }, ref) => { return ( <div> {label && <label>{label}</label>} {/* 把register返回的所有属性、ref直接传给原生input */} <input ref={ref} {...props} /> </div> ); }); // 父组件使用 import { useForm } from 'react-hook-form'; function Form() { const { register, handleSubmit } = useForm(); const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <InputField label="用户名" {...register('username')} /> <InputField label="密码" type="password" {...register('password')} /> <button type="submit">提交</button> </form> ); }
关键:forwardRef要将接收的ref直接绑定到内部原生input,同时通过...props传递register返回的所有属性(包括onChange、name、onBlur等),确保React Hook Form能跟踪输入值变化。
二、用Controller的正确实现
若Controller绑定无效,通常是未正确传入control,或是render函数内的value、onChange绑定错误。
示例代码:
import { Controller, useForm } from 'react-hook-form'; // 复用输入组件 const InputField = ({ label, value, onChange, ...props }) => { return ( <div> {label && <label>{label}</label>} <input value={value} onChange={(e) => onChange(e.target.value)} {...props} /> </div> ); }; // 父组件使用 function Form() { const { control, handleSubmit } = useForm(); const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="username" control={control} defaultValue="" render={({ field: { value, onChange } }) => ( <InputField label="用户名" value={value} onChange={onChange} /> )} /> <Controller name="password" control={control} defaultValue="" render={({ field: { value, onChange } }) => ( <InputField label="密码" type="password" value={value} onChange={onChange} /> )} /> <button type="submit">提交</button> </form> ); }
关键:
- 必须将
useForm返回的control传入Controller - 在
render函数中解构field对象,把value和onChange传递给复用组件 - 复用组件内部要将
value绑定到input,onChange需把输入值回传
三、通用型复用组件(适配两种绑定方式)
如果需要组件同时支持register和Controller,可通过判断props中的value和onChange区分模式:
import { forwardRef } from 'react'; const InputField = forwardRef(({ label, value, onChange, ...props }, ref) => { // Controller模式:手动绑定value和onChange if (value !== undefined && onChange) { return ( <div> {label && <label>{label}</label>} <input ref={ref} value={value} onChange={(e) => onChange(e.target.value)} {...props} /> </div> ); } // register模式:直接传递所有props return ( <div> {label && <label>{label}</label>} <input ref={ref} {...props} /> </div> ); });
这样组件既能配合register使用,也能适配Controller,实现多表单复用。
内容的提问来源于stack exchange,提问作者Danyx
相关产品推荐
相关产品推荐

