React Hook Form自定义Input组件无法接收props值问题求助
问题原因及解决方案
核心问题是你的自定义Input组件里单独调用了useForm(),这会生成一个独立的表单实例,和主组件的表单实例完全不共享状态——你在子组件里调用的setValue操作的是子组件自己的表单,根本不会影响主表单的输入框值,这就是同步失效、值异常的根本原因。
下面给两种可行的修复方案:
方案一:用官方推荐的useController实现自定义受控组件(优先选择)
这是React Hook Form官方为自定义受控组件提供的API,能完美和主表单实例集成,不需要手动维护同步逻辑。
修改Input组件:
import { useController } from "react-hook-form"; const Input = ({ control, name, label, errors }) => { const { field } = useController({ control, name, rules: { required: "This field is required!", minLength: { value: 5, message: "The field must be at least 5 characters" } } }); return ( <div className={`input`} > <label>{label}</label> <input {...field} /> {errors[name] && <span>{errors[name].message}</span>} </div> ); };
修改主Form组件:
去掉单独维护的title、description state,直接用reset方法设置接口返回的表单初始值,同时把主表单的control传给Input组件:
const FormTest = (props) => { const { control, handleSubmit, formState: { errors }, reset } = useForm(); const onSubmit = (data) => { console.log(data) } useEffect(() => { let random = Math.floor(Math.random() * 100) + 1; const fetchData = async () => { const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${random}`); const data = await response.json(); // 直接用reset设置整个表单的初始值 reset({ title: data.title, description: data.body }); } fetchData(); }, [reset]); return ( <div className="form-wrapper"> <h2 className="form-header">TEST</h2> <form onSubmit={handleSubmit(onSubmit)}> <Input name="title" label="Title" control={control} errors={errors} /> <Input name="description" label="description" control={control} errors={errors} /> <input type="submit"/> </form> </div> ); }
方案二:传递主表单的setValue给子组件
如果坚持用register方式,不要在子组件里调用useForm(),而是把主组件的setValue传进去,确保操作的是同一个表单实例。
修改Input组件:
const Input = ({ register, name, label, errors, initialValue, setValue }) => { useEffect(() => { // 避免初始undefined覆盖输入框,只在有有效值时同步 if (initialValue !== undefined) { setValue(name, initialValue); } }, [initialValue, name, setValue]) return ( <div className={`input`} > <label>{label}</label> <input {...register(name, { required: "This field is required!", minLength: { value: 5, message: "The field must be at least 5 characters" } })} /> {errors[name] && <span>{errors[name].message}</span>} </div> ); };
修改主Form组件:
把主表单的setValue作为props传给Input:
const FormTest = (props) => { const { register, handleSubmit, formState: { errors }, setValue } = useForm(); const [title, setTitle] = useState(); const [description, setDescription] = useState(); const onSubmit = (data) => { console.log(data) } useEffect(() => { let random = Math.floor(Math.random() * 100) + 1; const fetchData = async () => { const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${random}`); const data = await response.json(); setTitle(data.title); setDescription(data.body); } fetchData(); }, []); return ( <div className="form-wrapper"> <h2 className="form-header">TEST</h2> <form onSubmit={handleSubmit(onSubmit)}> <Input name="title" label="Title" register={register} errors={errors} initialValue={title} setValue={setValue} /> <Input name="description" label="description" register={register} errors={errors} initialValue={description} setValue={setValue} /> <input type="submit"/> </form> </div> ); }
内容的提问来源于stack exchange,提问作者Максим
相关产品推荐
相关产品推荐

