如何在TypeScript中整合intl-tel-input与React Hook Form Controller并实现错误聚焦?
解决方案:整合intl-tel-input React组件与React Hook Form Controller并实现自动聚焦
要解决这个问题,核心是让React Hook Form(RHF)的ref正确指向IntlTelInput内部的原生<input>元素,而非组件实例或覆盖组件内部的ref处理逻辑。以下是具体实现步骤:
问题根源
- 直接将RHF的
ref传给IntlTelInput组件的ref属性时,ref指向的是组件实例而非原生input元素,调用focus()自然会报错elm.focus is not a function。 - 通过
inputProps直接赋值ref会覆盖组件内部对input元素的ref绑定,导致组件无法正常渲染UI(如国旗选择器)。
正确实现方式
使用forwardRef转发ref,并通过IntlTelInput组件实例的getInput()方法获取原生input元素,将其关联到RHF传入的ref上:
1. 封装PhoneInput子组件(带forwardRef)
import React, { forwardRef, useEffect, useRef } from 'react'; import IntlTelInput from 'intl-tel-input-react'; import 'intl-tel-input/build/css/intlTelInput.css'; // 定义组件props类型 type PhoneInputProps = Omit<React.ComponentProps<typeof IntlTelInput>, 'ref'>; const PhoneInput = forwardRef<HTMLInputElement, PhoneInputProps>((props, externalRef) => { // 保存IntlTelInput组件实例的ref const itiInstanceRef = useRef<IntlTelInput | null>(null); useEffect(() => { if (itiInstanceRef.current && externalRef) { // 获取组件内部的原生input元素 const inputElement = itiInstanceRef.current.getInput(); // 将原生input元素关联到外部传入的ref(兼容函数式ref和对象式ref) if (typeof externalRef === 'function') { externalRef(inputElement); } else if (externalRef) { externalRef.current = inputElement; } } }, [externalRef]); return ( <IntlTelInput ref={itiInstanceRef} // 传递其他props,不要在inputProps中覆盖ref {...props} /> ); }); PhoneInput.displayName = 'PhoneInput'; export default PhoneInput;
2. 在父组件中使用Controller
import { Controller, useForm } from 'react-hook-form'; import PhoneInput from './PhoneInput'; type FormValues = { phoneE164: string; }; const MyForm = () => { const { control, handleSubmit, formState: { errors } } = useForm<FormValues>(); const onSubmit = (data: FormValues) => { console.log(data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller control={control} name="phoneE164" rules={{ required: '请输入手机号码' }} render={({ field }) => ( <div> <PhoneInput {...field} preferredCountries={['cn']} initialCountry="cn" /> {errors.phoneE164 && <span style={{ color: 'red' }}>{errors.phoneE164.message}</span>} </div> )} /> <button type="submit">提交</button> </form> ); }; export default MyForm;
原理说明
forwardRef允许子组件接收父组件传入的ref,并将其绑定到内部的原生input元素上。- 通过
itiInstanceRef获取IntlTelInput的组件实例,调用getInput()方法拿到真实的input DOM元素,确保RHF的ref指向正确的元素,调用focus()不会出错。 - 没有覆盖
inputProps中的ref,保留了组件内部的ref处理逻辑,因此UI不会出现异常。
内容的提问来源于stack exchange,提问作者Nacho Barral
相关产品推荐
相关产品推荐

