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

使用Yup验证与掩码时MUI TextField辅助文本失效问题求助

React Hook Form + MUI TextField 掩码输入辅助文本异常问题

预期行为

用户点击提交后,Yup按指定Schema验证表单,辅助文本显示无效输入的错误信息;用户输入合法值时,错误信息随输入实时验证自动消失。

问题描述

邮箱字段可正常实现上述逻辑,但带掩码的手机号TextField在首次提交触发错误后,错误提示永不消失,后续输入也无法触发重新验证。

Yup 验证Schema

const Schema = Yup.object().shape({
  email: Yup.string().required("Email is required").email(),
  cellPhone: Yup.number()
    .min(10, "Cell phone must have 10 digits at least")
    .max(12, "Cell phone must have 12 digits at max")
    .required("Cell phone is required")
    .typeError("Cell phone is required")
});

尝试的两种方案

方案1:react-input-mask 自定义掩码组件 + Controller

<Controller
  name="cellPhone"
  control={control}
  render={({ field: { onChange, value }, fieldState: { error } }) => (
    <InputMask mask="+99-999-9999999" value={value} onChange={onChange}>
      {(inputProps) => (
        <TextField
          {...inputProps}
          fullWidth
          label="Cell phone"
          error={!!error}
          helperText={error?.message}
        />
      )}
    </InputMask>
  )}
/>

方案2:material-ui-phone-number 组件 + Controller

<Controller
  name="cellPhone"
  control={control}
  render={({ name, onBlur, onChange, value, fieldState: { error } }) => (
    <MuiPhoneNumber
      name={name}
      value={value}
      onBlur={onBlur}
      onChange={onChange}
      defaultCountry="us"
      style={{ width: "100%" }}
      label="Cell phone"
      variant="outlined"
      margin="normal"
      error={!!error}
      helperText={error?.message}
    />
  )}
/>

两种方案均未达到预期效果,问题表现一致。


解决方案

核心问题分析

  1. 数据类型不匹配:掩码组件返回带格式的字符串(如+12-345-6789012),但Yup Schema中cellPhone定义为number类型,字符串无法通过数字类型校验,typeError会持续触发。
  2. 验证状态未更新:由于类型不匹配,React Hook Form的字段验证状态无法随输入同步更新,导致错误提示一直留存。

修复步骤

1. 修改Yup Schema,适配字符串类型

将cellPhone改为string类型,自定义校验逻辑过滤非数字字符并验证长度:

const Schema = Yup.object().shape({
  email: Yup.string().required("Email is required").email(),
  cellPhone: Yup.string()
    .required("Cell phone is required")
    .test(
      "digit-length",
      "Cell phone must have 10-12 digits",
      (value) => {
        if (!value) return false;
        const digits = value.replace(/\D/g, ""); // 移除所有非数字字符
        return digits.length >= 10 && digits.length <= 12;
      }
    )
});

2. 调整Controller的onChange逻辑,确保值同步正常

以react-input-mask为例,直接传递格式化后的字符串给React Hook Form:

<Controller
  name="cellPhone"
  control={control}
  render={({ field: { onChange, value }, fieldState: { error } }) => (
    <InputMask 
      mask="+99-999-9999999" 
      value={value || ""} 
      onChange={(e) => onChange(e.target.value)}
    >
      {(inputProps) => (
        <TextField
          {...inputProps}
          fullWidth
          label="Cell phone"
          error={!!error}
          helperText={error?.message}
        />
      )}
    </InputMask>
  )}
/>

3. 开启实时验证模式

在useForm配置中设置实时验证,确保输入时立即更新状态:

const { control, handleSubmit, formState: { errors } } = useForm({
  resolver: yupResolver(Schema),
  mode: "onChange" // 输入时实时触发验证
});

验证逻辑说明

  • 改用string类型适配掩码组件的输出格式;
  • 通过test方法自定义校验:先清理非数字字符,再判断有效数字长度是否符合要求;
  • 开启实时验证模式,确保输入动作能立即触发校验,错误提示及时更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:50:19