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

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,提问作者Максим

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:47:39