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

React-Hook-Form无法获取Select赋值的Input值问题解决

React-Hook-Form下拉框同步值到输入框后提交为空的解决方案

问题描述

使用React-Hook-Form开发表单时,设置了Select下拉框,选中选项后将值同步到名为customers的输入框,但提交表单时该输入框的值始终为空。

原代码示例

import { useState } from "react";
import { useForm } from "react-hook-form";

function App() {
const [inputs, setInputs] = useState();
const [inputs1, setInputs1] = useState();

const {
register,
formState: { errors },
trigger,
handleSubmit
} = useForm({
defaultValues: {
  searchby: "searchby",
  customers: "",
  firstName: ""
  }
 });

const onSubmit = (data) => {
alert(JSON.stringify(data));
};

const handleInputChanges = (event) => {
const name = event.target.name;
const value = event.target.value;
 setInputs(value);
 setInputs1(value);
};

  return (
<form onSubmit={handleSubmit(onSubmit)}>
  <select
    name="searchby"
    {...register("searchby", {
      required: "password is required."
    })}
    value={inputs}
    onChange={handleInputChanges}
  >
    <option selected value="searchby">
      Search By
    </option>
    <option value="customerID">Custimer ID </option>
    <option value="teleco">Teleco</option>
  </select>
  {errors.searchby && <p>This field is Required</p>}
  <label>Customer: </label>
  <input
    name="customers"
    {...register("customers")}
    value={inputs1}
    onChange={handleInputChanges}
  />

  {errors.customers && <p>This field is Required</p>}

  <label>First name: </label>
  <input {...register("firstName", { required: true })} />
  {errors.firstName && <p>This field is Required</p>}

  <input type="submit" />
  <button
    type="button"
 
      >
    Validate All
     </button>
    </form>
  );
  }

问题原因

  1. 表单状态追踪失效:通过本地useState维护inputs1并绑定到customers输入框的value,同时使用了React-Hook-Form的register,但自定义的onChange仅更新本地state,未通知React-Hook-Form更新表单数据,导致提交时RHF读取的还是customers字段的初始空值。
  2. 事件覆盖冲突:register方法会自动生成onChange事件追踪值变化,但自定义的onChange覆盖了该事件,进一步导致RHF无法感知customers输入框的数值变化。
  3. 逻辑错误:handleInputChanges会在下拉框和输入框变化时同时更新inputs和inputs1,导致输入框手动输入的内容被下拉框的值覆盖,逻辑混乱。

解决方案

方案一:使用setValue同步表单状态(轻量场景推荐)

通过React-Hook-Form提供的setValue方法,在下拉框变化时直接更新customers字段的表单值,让RHF能追踪到数值变化。

修正后代码:

import { useState } from "react";
import { useForm, useWatch } from "react-hook-form";

function App() {
  // 初始化下拉框默认值为defaultValues中的值
  const [inputs, setInputs] = useState("searchby");
  const {
    register,
    formState: { errors },
    handleSubmit,
    setValue, // 新增:手动更新表单字段
    watch, // 新增:监听表单字段实时值
    trigger // 手动触发校验
  } = useForm({
    defaultValues: {
      searchby: "searchby",
      customers: "",
      firstName: ""
    }
  });

  const onSubmit = (data) => {
    alert(JSON.stringify(data));
  };

  const handleInputChanges = (event) => {
    const name = event.target.name;
    const value = event.target.value;
    setInputs(value);
    // 仅当下拉框变化时,同步更新customers表单字段
    if (name === "searchby") {
      setValue("customers", value);
    }
  };

  // 监听customers字段的实时值,用于输入框显示
  const customerValue = watch("customers");

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <select
        name="searchby"
        {...register("searchby", {
          required: "This field is required." // 修正错误提示文案
        })}
        value={inputs}
        onChange={handleInputChanges}
      >
        <option value="searchby">Search By</option>
        <option value="customerID">Customer ID</option>
        <option value="teleco">Teleco</option>
      </select>
      {errors.searchby && <p>{errors.searchby.message}</p>}

      <label>Customer: </label>
      <input
        name="customers"
        {...register("customers")}
        value={customerValue} // 使用watch获取的表单值,而非本地state
      />
      {errors.customers && <p>This field is Required</p>}

      <label>First name: </label>
      <input {...register("firstName", { required: true })} />
      {errors.firstName && <p>This field is Required</p>}

      <input type="submit" />
      <button type="button" onClick={() => trigger()}>
        Validate All
      </button>
    </form>
  );
}

export default App;

关键修改点:

  • 从useForm解构setValue和watch,用setValue更新表单字段,watch获取实时值
  • 调整handleInputChanges逻辑,仅在下拉框变化时同步customers值
  • 输入框value绑定watch返回的表单值,确保显示与RHF状态一致
  • 去掉多余的inputs1本地状态,统一用RHF管理表单数据
  • 修复下拉框的错误提示文案,给Validate按钮添加手动校验逻辑

方案二:使用Controller组件(复杂受控场景推荐)

对于需要手动控制的组件,React-Hook-Form推荐使用Controller组件包裹,它能帮助RHF完全追踪组件的状态变化,避免自定义事件冲突。

核心代码片段:

// 从useForm解构control
const {
  register,
  formState: { errors },
  handleSubmit,
  control,
  setValue,
  trigger
} = useForm({
  defaultValues: {
    searchby: "searchby",
    customers: "",
    firstName: ""
  }
});

// 下拉框变化时直接更新customers字段
const handleSelectChange = (event) => {
  const value = event.target.value;
  setInputs(value);
  setValue("customers", value);
};

// 用Controller包裹customers输入框
<Controller
  name="customers"
  control={control}
  rules={{ required: true }} // 可添加校验规则
  render={({ field }) => (
    <input
      {...field}
      placeholder="Customer"
    />
  )}
/>

优势:

  • Controller自动处理value和onChange,无需手动维护状态
  • 支持直接配置校验规则,与RHF的校验体系完全兼容
  • 避免自定义事件与RHF内置事件的冲突

验证效果

提交表单时,customers字段会正确携带下拉框选中的值,表单数据能正常被RHF捕获。

内容的提问来源于stack exchange,提问作者kick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:31:04