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

如何使用react-hook-form为表单输入项添加状态并实现数据更新存储

问题原因分析
  • 事件处理函数逻辑错误:你当前写的handleNorthDistanceValue直接把原状态值重新赋值给状态,没有读取输入框最新值,自然不会触发状态更新
  • FormField组件未支持受控模式:输入框使用了defaultValue(非受控组件属性),没有绑定value属性到传入的props,同时没有透传父组件传入的onChange事件到内部input
  • 钩子使用违规:你之前注释的代码里把useEffect写在了事件处理函数内部,违反了React钩子只能在组件顶层调用的规则
  • React Hook Form与自定义状态冲突:register方法已经默认接管了表单值的管理,你要同时维护自定义状态需要同步两者的更新逻辑
修复步骤

1. 首先修改FormField组件,支持受控模式和自定义onChange

先更新FormFieldProps类型,添加onChange属性:

export type FormFieldProps = {
  // 原有属性不变
  /**
   * 输入值变化时的回调函数
   */
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
}

然后修改FormField组件内部input的渲染逻辑:

const FormField: FunctionComponent<FormFieldProps> = (props) => {
  const {
    // 原有解构不变
    onChange,
  } = props

  // 先处理register返回的属性
  const reg = register(`${name}`, {
    ...rules,
  })

  // 合并onChange事件,同时触发RHF的更新和自定义回调
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    reg.onChange(e)
    onChange?.(e)
  }

  const form_field = (
    <div className={['form__field', className].join(' ')}>
      {label && <FormLabel text={label} forID={name} />}

      <input
        id={name}
        className={`form__input ${readonly ? 'form__path' : ''}`}
        placeholder={placeholder as string}
        // 受控模式用value绑定,不要用defaultValue
        value={value ?? defaultValue}
        required={required}
        type={type}
        disabled={disabled}
        readOnly={readonly}
        step={step}
        // 展开reg其他属性,替换自定义onChange
        {...reg}
        onChange={handleInputChange}
      />
    </div>
  )
  // 剩余逻辑不变
}

2. 修复父组件的状态更新逻辑

删除错误的事件处理函数,替换为读取输入值的逻辑:

const PlanDistanceFieldset: FunctionComponent<PlanDistanceFieldsetProps> = (
  props
) => {
  const {register} = props
  const [showTip, setShowTip] = useState<boolean>(false)
  const [northDistance, setNorthDistanceValue] = useState(800)
  const [eastDistance, setEastDistanceValue] = useState(defaultDistancePlan.distanceEastValue)

  // 正确的更新逻辑,读取输入框最新值转成数字更新状态
  const handleNorthDistanceChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setNorthDistanceValue(Number(e.target.value))
  }
  const handleEastDistanceChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setEastDistanceValue(Number(e.target.value))
  }

  // 调试用的useEffect要写在组件顶层
  useEffect(() => {
    console.log('north', northDistance)
  }, [northDistance]);
  useEffect(() => {
    console.log('east', eastDistance)
  }, [eastDistance]);

  return (
    <>
      <div className={'form__parameter_row_wrapper'}>
        <div className={'form__parameter_field'}>
          <FormLabel text={'Plan Distance [m]'} />
        </div>
        <FormField
          label={'North-South Distance'}
          type={'number'}
          name={'north_south_distance'}
          value={northDistance}
          onChange={handleNorthDistanceChange}
          required={true}
          register={register}
        />
        <FormField
          label={'East-West Distance'}
          type={'number'}
          name={'east_west_distance'}
          value={eastDistance}
          onChange={handleEastDistanceChange}
          required={true}
          register={register}
        />
        <ToolTip
          onClick={() => {
            setShowTip(true)
          }}
        />
      </div>
    </>
  )
}
补充说明

如果你不需要独立维护这两个值的状态,完全可以直接用React Hook Form内置的方法获取值,不用自己写useState:

  • 用useWatch('north_south_distance')可以实时获取输入框的值
  • 用setValue方法可以手动修改表单值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 06:06:03