如何在react-imask、react-bootstrap与react-hook-form间共享Ref?
解决IMask包装的FormControl与react-hook-form兼容问题
问题核心
react-hook-form的register方法返回的ref需要绑定到真实的input元素,但IMaskMixin通过inputRef占用了input的引用绑定,同时组件还要兼容使用/不使用react-hook-form两种场景,导致值无法正确同步。
解决方案
修改MaskedFormControl组件,通过forwardRef接收外部传入的ref(包括react-hook-form的ref),同时合并IMask与react-hook-form的onChange逻辑,确保值能正确传递。
改造后的组件代码
import { IMaskMixin } from 'react-imask'; import { FormControl } from 'react-bootstrap'; import { forwardRef } from 'react'; const MaskedFormControl = IMaskMixin( forwardRef(({ inputRef, onChange: imaskOnChange, ...props }, externalRef) => { // 合并IMask与外部(react-hook-form/手动)的onChange逻辑 const handleChange = (e) => { // 先执行IMask自带的onChange(如果有) if (imaskOnChange) imaskOnChange(e); // 获取IMask解析后的原始值(unmaskedValue),如需格式化值可改用e.target.value const rawValue = e.target.unmaskedValue; // 触发外部传入的onChange(比如react-hook-form的onChange) if (props.onChange) { props.onChange({ target: { name: props.name, value: rawValue } }); } }; // 同时绑定IMask的inputRef和外部传入的ref(比如react-hook-form的ref) const combinedRef = (el) => { // 给IMask传递input引用 inputRef(el); // 处理外部ref:兼容函数式ref和对象式ref if (typeof externalRef === 'function') { externalRef(el); } else if (externalRef) { externalRef.current = el; } }; return ( <FormControl {...props} ref={combinedRef} onChange={handleChange} /> ); }) );
使用示例
1. 与react-hook-form配合使用
import { useForm } from 'react-hook-form'; function RHFExampleForm() { const { register, handleSubmit } = useForm(); const onSubmit = (formData) => { console.log('表单数据:', formData); // 这里拿到的是IMask解析后的原始值 }; return ( <form onSubmit={handleSubmit(onSubmit)}> <MaskedFormControl {...register('phone')} mask="+{86}(000)0000-0000" // IMask的掩码配置 placeholder="请输入手机号" /> <button type="submit">提交</button> </form> ); }
2. 不使用react-hook-form的手动场景
import { useState } from 'react'; function ManualExampleForm() { const [phone, setPhone] = useState(''); const handlePhoneChange = (e) => { setPhone(e.target.unmaskedValue); // 直接获取原始值 }; return ( <MaskedFormControl value={phone} onChange={handlePhoneChange} mask="+{86}(000)0000-0000" placeholder="请输入手机号" /> ); }
关键细节说明
- ref合并:通过
combinedRef同时将真实input的引用传递给IMask和外部(react-hook-form),确保双方都能拿到正确的input元素。 - 值同步:通过
e.target.unmaskedValue获取IMask解析后的原始值,避免react-hook-form存储格式化后的掩码值(如带括号的手机号)。 - 兼容性:同时支持受控/非受控模式,以及函数式ref和对象式ref,覆盖所有使用场景。
内容的提问来源于stack exchange,提问作者user210757
相关产品推荐
相关产品推荐

