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

react-hook-form的Controller包裹多输入自定义组件出错如何实现聚焦?

原因说明

react-hook-form 默认的错误聚焦逻辑是通过字段name匹配对应DOM元素实现的,你当前将两个输入框绑定在同一个Controller的name="name"下,框架无法定位到具体的错误输入框,因此默认聚焦失效。

解决步骤

1. 修改Form.js逻辑

  • 禁用默认错误聚焦配置
  • 新增提交失败的错误处理回调
  • 通过ref获取自定义组件实例,调用对应输入框的聚焦方法
import { Controller, useForm } from "react-hook-form";
import CustomInput from "./CustomInput";
import * as yup from "yup";
import { yupResolver } from '@hookform/resolvers/yup';
import { useRef } from "react";

const schema = yup.object({
  name: yup.object().shape({
    first: yup.string().required("first name不能为空"),
    last: yup.string().required("last name不能为空"),
  }),
});
function Form() {
  const customInputRef = useRef(null);
  const {
    handleSubmit,
    control,
    formState: { errors },
  } = useForm({
    defaultValues: { name: { first: "", last: "" } },
    resolver: yupResolver(schema),
    shouldFocusError: false, // 禁用默认错误聚焦
  });

  const onSubmit = (data) => console.log(data);

  // 提交校验失败回调
  const onError = (errors) => {
    if (errors.name) {
      // 优先聚焦第一个出错的输入框
      if (errors.name.first) {
        customInputRef.current?.focusFirst();
      } else if (errors.name.last) {
        customInputRef.current?.focusLast();
      }
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit, onError)}>
      <Controller
        name="name"
        control={control}
        render={({ field }) => (
          <CustomInput
            ref={customInputRef}
            value={field.value}
            onChange={(value) => field.onChange(value)}
            errors={errors}
          />
        )}
      />
      <button type="submit">提交</button>
    </form>
  );
}

export default Form;

2. 修改CustomInput.js逻辑

  • 用forwardRef包裹组件接收父组件传的ref
  • 用useImperativeHandle暴露聚焦方法给父组件调用
import { forwardRef, useImperativeHandle, useRef } from "react";

const CustomInput = forwardRef(({ value, onChange, errors }, ref) => {
  const firstInputRef = useRef(null);
  const lastInputRef = useRef(null);

  // 暴露聚焦方法给父组件
  useImperativeHandle(ref, () => ({
    focusFirst: () => firstInputRef.current?.focus(),
    focusLast: () => lastInputRef.current?.focus()
  }));

  const changeFirst = (e) => {
    onChange({ first: e.target.value, last: value?.last });
  };

  const changeLast = (e) => {
    onChange({ first: value?.first, last: e.target.value });
  };

  return (
    <div>
      <input ref={firstInputRef} type="text" value={value.first} onChange={changeFirst} />
      <input ref={lastInputRef} type="text" value={value.last} onChange={changeLast} />
      {errors?.name && (
        <p className="errmsg">
          {errors?.name?.first?.message || errors?.name?.last?.message}
        </p>
      )}
    </div>
  );
});

export default CustomInput;

扩展说明

如果自定义组件内的输入框数量更多,只需要对应新增ref和聚焦方法,在错误回调里按错误的嵌套字段判断优先级,调用对应聚焦方法即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 17:15:05