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

使用Formik限制react-phone-number-input输入长度时输入框仍更新的问题

问题:react-phone-number-input与Formik集成时输入长度限制失效

我在项目中集成了react-phone-number-input和Formik库,希望将手机号输入长度限制为18位。以下是我使用的逻辑:

<PhoneNumberInput
          id="patient.phone.number"
          values={number}
          errors={phoneNumberError}
          touched={phoneNumberTouched}
          onBlur={handleBlur}
          onChange={(num: string | null) => phoneNumberHandler(num)}
          placeholder={t('profile.phone')}
          label={t('profile.phone')}
        />

  const phoneNumberHandler = (num: string | null) => {
    if (num && num.length >= 18) return;
    if (num && num.length < 18) {
      console.log('num', num);
      const phoneNumber = parsePhoneNumber(num);
      console.log('phoneNumber', phoneNumber);
      if (phoneNumber) {
        formik.setValues({
          ...formik.values,
          patient: {
            ...formik.values.patient,
            phone: {
              number: phoneNumber.number,
              region: phoneNumber?.country || '',
              countryCode: phoneNumber?.countryCallingCode || '',
            },
          },
        });
      }
    }
  };

奇怪的是,当num.length>=18时,console.log('num')、console.log('phoneNumber')以及Formik的values都不再更新,从这一角度看代码似乎正常,但不知为何屏幕上的手机号输入框内容却一直在更新,不受num.length的影响。请问我的代码哪里存在错误?


问题原因

你只在phoneNumberHandler里拦截了Formik的值更新,但react-phone-number-input组件自身的内部状态并没有被限制。组件会独立维护输入框的显示内容,当你在输入长度达标后直接return,没有将最新的输入值同步回组件的受控状态,导致组件内部状态继续更新,而Formik的值停留在17位,最终出现显示内容和实际存储值不一致的情况。

另外你代码里的PhoneNumberInput属性写错了,应该是value={number}而非values={number},这也是组件状态不受控的诱因之一。

解决方法

让PhoneNumberInput成为完全受控组件,确保组件显示值始终和Formik的values保持一致,同时主动截断超过18位的输入内容:

<PhoneNumberInput
  id="patient.phone.number"
  value={number} // 修正属性名
  errors={phoneNumberError}
  touched={phoneNumberTouched}
  onBlur={handleBlur}
  onChange={(num: string | null) => phoneNumberHandler(num)}
  placeholder={t('profile.phone')}
  label={t('profile.phone')}
/>

const phoneNumberHandler = (num: string | null) => {
  if (!num) {
    formik.setValues({
      ...formik.values,
      patient: {
        ...formik.values.patient,
        phone: {
          ...formik.values.patient.phone,
          number: '',
        },
      },
    });
    return;
  }

  // 先截断到18位以内
  const truncatedNum = num.slice(0, 18);
  const phoneNumber = parsePhoneNumber(truncatedNum);
  
  if (phoneNumber) {
    formik.setValues({
      ...formik.values,
      patient: {
        ...formik.values.patient,
        phone: {
          number: phoneNumber.number,
          region: phoneNumber?.country || '',
          countryCode: phoneNumber?.countryCallingCode || '',
        },
      },
    });
  }
};

关键说明

  • 不要在输入超长度时直接return,而是主动截断内容并同步到Formik,这样组件的显示值会和Formik的值强制保持一致
  • 必须确保组件的value属性绑定到Formik的存储值,让组件完全受控于外部状态

内容的提问来源于stack exchange,提问作者marcinb1986

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 00:47:10