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

React Hook Form表单数据无法传递问题排查与解决求助

React Hook Form提交数据全为undefined的问题排查与修复

使用React Hook Form进行表单验证时,提交表单后onSubmit接收的data所有字段均为undefined,相关代码及修复方案如下:

表单组件代码

<form onSubmit={handleSubmit(onSubmit)}>
  <FormGroup className="mb-3">
    <FormText>Full Name</FormText>
    <Input
      id="fullName"
      className="input-transparent pl-3"
      type="text"
      style={{ border: inputError ? "1px solid red" : "" }}
      name="fullName"
      placeholder="Henry"
      onChange={(e) => handleChange(e, setFormData)}
      {...register("fullName", { name: "fullName" })}
      defaultValue={fullName}
    />
    {errors.fullName && <small>This field is required</small>}
  </FormGroup>
  <FormGroup className="my-3">
    <FormText>Email</FormText>
    <Input
      id="email"
      className="input-transparent pl-3"
      type="text"
      name="email"
      placeholder="henrymonk@mail.com"
      onChange={(e) => handleChange(e, setFormData)}
      {...register("email", { name: "email" })}
      defaultValue={email}
    />
    {errors.email && <small>This field is required</small>}
  </FormGroup>
  <FormGroup className="my-3">
    <FormText>Phone Number</FormText>
    <Input
      id="phone"
      className="input-transparent pl-3"
      type="text"
      name="phone"
      placeholder="+123456789"
      onChange={(e) => handleChange(e, setFormData)}
      {...register("phone", { name: "phone" })}
      defaultValue={phone}
    />
    {errors.phone && <small>This field is required</small>}
  </FormGroup>
  
  <FormGroup className="my-3">
    <div className="d-flex justify-content-between">
      <FormText></FormText>
      {/* <Link to="/error">Forgot password?</Link> */}
    </div>
    <FileUploader
      content={`Upload Photo`}
      icon={`image`}
      onChange={handleFileSelect}
    />
  </FormGroup>
  <FormGroup className="my-3">
    <div className="d-flex justify-content-between">
      <FormText>Password</FormText>
      <Link to="/error">Forgot password?</Link>
    </div>
    <InputGroup>
      <Input
        id="password"
        className="input-transparent pl-3"
        style={{ borderRight: "none" }}
        type={showPassword === true ? 'text' : 'password'}
        name="password"
        placeholder="Place your password here"
        onChange={(e) => handleChange(e, setFormData)}
        {...register("password", { name: "password" })}
        defaultValue={password}
      />
      <Button
        color="white"
        onClick={handleShowPassword}
        style={{
          margin: 0,
          padding: "0px 20px",
          justifyContent: "center",
          alignItems: "center",
          borderTopLeftRadius: 0,
          borderBottomLeftRadius: 0,
          borderRight: "1px solid #6b859e65",
          borderBlock: "1px solid #6b859e65",
        }}
      >
        <i className={showPassword === false ? `eva eva-eye-outline` : `eva eva-eye-off-outline`} />
      </Button>
    </InputGroup>
    {errors.password && <small>This field is required</small>}
  </FormGroup>
  
  <div className="bg-widget d-flex justify-content-center">
    <Button
      className="rounded-pill my-3"
      type="submit"
      color="secondary-red"
    >
      Sign Up
    </Button>
  </div>
  <p className="dividing-line my-3">&#8195;Or&#8195;</p>
  <div className="d-flex align-items-center my-3">
    <p className="social-label mb-0">Login with</p>
    <div className="socials">
      <a href="https://flatlogic.com/">
        <GoogleIcon />
      </a>
      <a href="https://flatlogic.com/">
        <GithubIcon />
      </a>
    </div>
    <Link to="/login">Enter your Cradev account</Link>
  </div>
  
</form>

相关函数与状态

const [formData, setFormData] = useState({
  email: '',
  fullName: '',
  password: '',
  phone: '',
});

const onSubmit = async (data) => {
  try {
    console.log("data", data)
    await dispatch(registerUser(data)).unwrap();
   // props.history.push("/template");
  } catch (error) {
    const errorMessages = error?.errors?.map((err) => err.msg);
    toast.error(errorMessages.join("\n"), {
      theme: "colored",
    });
  }
};

const handleChange = (event, setValue) => {
  const { name, value } = event.target;
  console.log(formData)
  setValue((prevState) => ({ ...prevState, [name]: value }));
};

问题原因

  1. 模式冲突:同时混用React Hook Form的register(非受控模式)和自定义useState+onChange(受控模式),手动添加的onChange会覆盖register绑定的监听逻辑,导致React Hook Form无法捕获输入值。
  2. register参数错误:register("fullName")已自动设置name属性,无需额外传{ name: "fullName" };且代码中先写自定义onChange再展开register,若register返回的对象包含onChange会被覆盖,阻断表单状态跟踪。
  3. 默认值配置不当:单独给每个输入框设defaultValue不符合React Hook Form的非受控模式规范,应在useForm初始化时统一设置defaultValues。
  4. 自定义组件ref传递问题:若Input是自定义组件,未正确将ref传递给内部原生input元素,会导致register无法获取DOM元素跟踪值变化。

修复方案

方案一:完全使用React Hook Form非受控模式(推荐)

移除自定义状态和handleChange,让React Hook Form全权管理表单:

  1. 初始化useForm时设置默认值:
const { register, handleSubmit, formState: { errors } } = useForm({
  defaultValues: {
    email: '',
    fullName: '',
    password: '',
    phone: '',
  }
});
  1. 修改输入框,移除onChange、defaultValue和手动name:
<Input
  id="fullName"
  className="input-transparent pl-3"
  type="text"
  style={{ border: inputError ? "1px solid red" : "" }}
  placeholder="Henry"
  {...register("fullName", { required: true })}
/>

(其他输入框同理调整)

  1. 直接使用onSubmit接收的data即可,无需维护自定义状态。

方案二:使用受控模式(配合Controller组件)

若需保留自定义状态,用Controller包裹输入框实现状态同步:

  1. 初始化useForm关联自定义状态:
const { control, handleSubmit, formState: { errors } } = useForm({
  defaultValues: formData
});
  1. 用Controller包裹输入框:
<Controller
  name="fullName"
  control={control}
  rules={{ required: true }}
  render={({ field }) => (
    <Input
      id="fullName"
      className="input-transparent pl-3"
      type="text"
      style={{ border: inputError ? "1px solid red" : "" }}
      placeholder="Henry"
      {...field}
      onChange={(e) => {
        field.onChange(e); // 同步React Hook Form状态
        setFormData(prev => ({ ...prev, fullName: e.target.value })); // 同步自定义状态
      }}
    />
  )}
/>

额外注意点

  • 自定义Input组件需确保能传递value、onChange、ref到内部原生input元素,否则register或Controller无法正常工作。
  • 验证规则可直接写在register或Controller的rules属性中。

内容的提问来源于stack exchange,提问作者Mohamed Amine Boudagga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:47:07