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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 00:16:13