使用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} /> )} />
两种方案均未达到预期效果,问题表现一致。
解决方案
核心问题分析
- 数据类型不匹配:掩码组件返回带格式的字符串(如
+12-345-6789012),但Yup Schema中cellPhone定义为number类型,字符串无法通过数字类型校验,typeError会持续触发。 - 验证状态未更新:由于类型不匹配,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
相关产品推荐
相关产品推荐

