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
相关产品推荐
相关产品推荐

