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

React Hook Form复用组件报错:无法给函数组件传refs

解决React Hook Form复用输入组件的绑定问题

一、用forwardRef配合register的正确实现

提交值不更新的核心原因,大多是没把register返回的属性完整传递给原生输入框,或是forwardRef未正确关联到内部的原生input。

示例代码:

import { forwardRef } from 'react';

// 复用输入组件
const InputField = forwardRef(({ label, ...props }, ref) => {
  return (
    <div>
      {label && <label>{label}</label>}
      {/* 把register返回的所有属性、ref直接传给原生input */}
      <input ref={ref} {...props} />
    </div>
  );
});

// 父组件使用
import { useForm } from 'react-hook-form';

function Form() {
  const { register, handleSubmit } = useForm();
  
  const onSubmit = (data) => console.log(data);
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <InputField label="用户名" {...register('username')} />
      <InputField label="密码" type="password" {...register('password')} />
      <button type="submit">提交</button>
    </form>
  );
}

关键:forwardRef要将接收的ref直接绑定到内部原生input,同时通过...props传递register返回的所有属性(包括onChange、name、onBlur等),确保React Hook Form能跟踪输入值变化。

二、用Controller的正确实现

若Controller绑定无效,通常是未正确传入control,或是render函数内的value、onChange绑定错误。

示例代码:

import { Controller, useForm } from 'react-hook-form';

// 复用输入组件
const InputField = ({ label, value, onChange, ...props }) => {
  return (
    <div>
      {label && <label>{label}</label>}
      <input 
        value={value} 
        onChange={(e) => onChange(e.target.value)} 
        {...props} 
      />
    </div>
  );
};

// 父组件使用
function Form() {
  const { control, handleSubmit } = useForm();
  
  const onSubmit = (data) => console.log(data);
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="username"
        control={control}
        defaultValue=""
        render={({ field: { value, onChange } }) => (
          <InputField label="用户名" value={value} onChange={onChange} />
        )}
      />
      <Controller
        name="password"
        control={control}
        defaultValue=""
        render={({ field: { value, onChange } }) => (
          <InputField label="密码" type="password" value={value} onChange={onChange} />
        )}
      />
      <button type="submit">提交</button>
    </form>
  );
}

关键:

  • 必须将useForm返回的control传入Controller
  • 在render函数中解构field对象,把value和onChange传递给复用组件
  • 复用组件内部要将value绑定到input,onChange需把输入值回传

三、通用型复用组件(适配两种绑定方式)

如果需要组件同时支持register和Controller,可通过判断props中的value和onChange区分模式:

import { forwardRef } from 'react';

const InputField = forwardRef(({ label, value, onChange, ...props }, ref) => {
  // Controller模式:手动绑定value和onChange
  if (value !== undefined && onChange) {
    return (
      <div>
        {label && <label>{label}</label>}
        <input 
          ref={ref} 
          value={value} 
          onChange={(e) => onChange(e.target.value)} 
          {...props} 
        />
      </div>
    );
  }
  // register模式:直接传递所有props
  return (
    <div>
      {label && <label>{label}</label>}
      <input ref={ref} {...props} />
    </div>
  );
});

这样组件既能配合register使用,也能适配Controller,实现多表单复用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:35:25