React IMask手机号掩码与React Hook Form联动值更新异常求助
React Hook Form 搭配 IMask 手机号掩码值同步问题解决
问题描述
使用IMask实现手机号输入掩码功能,结合React Hook Form管理表单时出现值更新异常:输入1234567后,掩码显示123-45-67,但表单返回值不正确,控制台抛出提示:
Element value was changed outside of mask. Syncronize mask using
mask.updateValue()to work properly.
尝试调用updateValue()同步但未成功,需提供正确实现方案。
原相关代码
主组件代码
const {handleSubmit, register, control, formState: { errors },} = useForm({ resolver: yupResolver(schema), }); const phoneInput = useMemo( () => ( <PhoneMaskInput control={control} register={register} name="phone" inputName="Mobil nömrəniz" id="phone" placeholder="Mobil nömrə" required error={errors?.phone?.message} /> ), [errors.phone], ); <form onSubmit={handleSubmit(onSubmit)} noValidate> {phoneInput} <button type="submit">Daxil olun</button> </form>
IMask组件代码
import { useRef } from 'react'; import { IMaskInput } from 'react-imask'; import { Controller } from 'react-hook-form'; const PhoneMaskInput = ({ control, name, inputName, placeholder }) => { const ref = useRef(null); const inputRef = useRef(null); return ( <div className="input-container"> <Controller name={name} control={control} defaultValue="" render={({ field }) => ( <IMaskInput mask="000-00-00" placeholder={placeholder} unmask={true} ref={ref} {...field} classID={id} className="imask-input" inputRef={inputRef} onAccept={(value) => field.onChange(value)} /> )} /> </div> ); }; export default PhoneMaskInput;
修正后的实现方案
问题根源
{...field}传入的React Hook Form原生onChange,与IMask的onAccept逻辑冲突,导致值同步混乱- 未监听表单值的外部修改(如重置、初始化),无法同步到IMask输入框
- Ref绑定错误,无法获取IMask实例调用
updateValue()完成同步
修正后的IMask组件代码
import { useRef, useEffect } from 'react'; import { IMaskInput } from 'react-imask'; import { Controller } from 'react-hook-form'; const PhoneMaskInput = ({ control, name, placeholder, error }) => { // 存储IMask实例的ref const maskRef = useRef(null); return ( <div className="input-container"> <Controller name={name} control={control} defaultValue="" render={({ field: { value, onChange, ref } }) => { // 监听表单值变化,同步到IMask输入框 useEffect(() => { if (maskRef.current) { maskRef.current.updateValue(value); } }, [value]); return ( <> <IMaskInput // 绑定IMask实例到maskRef ref={maskRef} // 挂载原生input的ref到React Hook Form的ref inputRef={ref} mask="000-00-00" placeholder={placeholder} unmask={true} className={`imask-input ${error ? 'error' : ''}`} // 仅通过IMask的onAccept更新表单值 onAccept={(unmaskedValue) => onChange(unmaskedValue)} /> {error && <span className="error-message">{error}</span>} </> ); }} /> </div> ); }; export default PhoneMaskInput;
主组件代码调整
const {handleSubmit, control, formState: { errors },} = useForm({ resolver: yupResolver(schema), }); // 修正useMemo依赖,添加control确保组件正确更新 const phoneInput = useMemo( () => ( <PhoneMaskInput control={control} name="phone" placeholder="Mobil nömrə" error={errors?.phone?.message} /> ), [control, errors.phone], ); <form onSubmit={handleSubmit(onSubmit)} noValidate> {phoneInput} <button type="submit">Daxil olun</button> </form>
关键优化点
- 分离Ref职责:
maskRef存储IMask实例,inputRef绑定React Hook Form需要的原生input节点,避免逻辑冲突 - 统一值更新逻辑:仅通过IMask的
onAccept回调更新表单值,消除重复触发问题 - 同步外部值修改:添加
useEffect监听表单值变化,主动调用updateValue()同步到IMask输入框,解决控制台报错 - 修正依赖项:主组件
useMemo添加control依赖,确保组件在表单控制实例变化时正确更新
内容的提问来源于stack exchange,提问作者Rahil Əliyev
相关产品推荐
相关产品推荐

