使用@mui/x-date-pickers与Formik时错误消息不显示的问题
问题:MUI DatePicker结合Formik时,手动输入过去日期不显示错误提示
在React项目中使用@mui/x-date-pickers的DatePicker组件,结合Formik做表单验证时,手动输入过去的日期,错误消息无法正常显示。相关代码如下:
DatePicker组件代码
<LocalizationProvider adapterLocale={locale} dateAdapter={AdapterDayjs} > <DatePicker label={t('test.form.license-expiry-date')} id={t('test.form.license-expiry-date')} name="dLExpDate" value={dayjs(values.dLExpDate)} onChange={date => { if (date) { const newDate = date.toDate(); const formattedStartDate = format(newDate, 'dd-MM-yyyy'); handleChange('dLExpDate')(formattedStartDate); // Set the field as touched setFieldTouched('dLExpDate', true, false); // Simulate onBlur behavior if (!errors.dLExpDate) { props.setFieldValue( 'dLExpDate', transformDateString(formattedStartDate) ); } } else { // Handle the case when the date is deleted handleChange('dLExpDate')(''); setFieldTouched('dLExpDate', true, false); props.setFieldValue('dLExpDate', null); // Set to null or handle as needed } }} disablePast="true" orientation="portrait" error={errors.dLExpDate && touched.dLExpDate} helperText={touched.dLExpDate && errors.dLExpDate} /> </LocalizationProvider>
Formik配置代码
<Formik initialValues={{ dLExpDate: null, }} validationSchema={validator({ dLExpDate: { validatorKey: 'dLExpDate', required: true, }, })} > {/* Other form components */} </Formik>
Yup验证规则代码
dLExpDate: function (t) { return Yup.string() .oneOfLengths([10], t('test.error.date')) .matches(dateRegExp, t('test.error.date')) .test('date', 'Invalid date. Must be today or later', function (value) { if (!value) { return true; // Skip validation if the value is empty } const selectedDate = new Date(value); const currentDate = new Date(); debugger; return selectedDate >= currentDate; }); },
尽管已将字段设为已触碰状态,且配置了error={errors.dLExpDate && touched.dLExpDate}的错误显示条件,但错误消息仍未显示。
原因分析
- 字段更新逻辑冲突:
onChange中先调用handleChange设置格式化日期,之后又通过props.setFieldValue修改字段值,两次更新可能导致Formik的验证流程未正常触发,errors对象未更新。 disablePast属性类型错误:设置为字符串"true"而非布尔值true,虽然不影响手动输入,但属于配置错误,可能引发其他潜在问题。- 日期解析兼容性问题:用原生
new Date(value)解析dd-MM-yyyy格式字符串,部分浏览器会解析错误,导致日期比较结果不正确,验证逻辑误判为合法日期。 - 验证触发时机未对齐:虽然调用了
setFieldTouched,但字段值更新后未触发Formik的重新验证,errors未同步更新,导致错误提示不渲染。
解决建议
1. 修正disablePast属性类型
将disablePast="true"改为disablePast={true},确保是布尔值配置:
<DatePicker // ...其他属性 disablePast={true} />
2. 简化onChange逻辑,确保验证触发
去掉冗余的字段更新操作,直接用Formik的setFieldValue和setFieldTouched,避免多次修改导致的验证异常:
onChange={date => { const formattedDate = date ? date.format('DD-MM-YYYY') : null; setFieldValue('dLExpDate', formattedDate); setFieldTouched('dLExpDate', true); }}
3. 修复Yup验证中的日期解析问题
改用dayjs解析日期,避免原生Date的兼容性问题,同时统一日期比较逻辑:
dLExpDate: function (t) { return Yup.string() .oneOfLengths([10], t('test.error.date')) .matches(dateRegExp, t('test.error.date')) .test('date', 'Invalid date. Must be today or later', function (value) { if (!value) return true; // 使用dayjs指定格式解析,确保正确性 const selectedDate = dayjs(value, 'DD-MM-YYYY'); if (!selectedDate.isValid()) return false; // 取当天起始时间,避免时分秒影响比较结果 const currentDate = dayjs().startOf('day'); return selectedDate.isAfter(currentDate) || selectedDate.isSame(currentDate); }); },
4. 调试验证状态
在DatePicker组件中添加日志,确认errors.dLExpDate和touched.dLExpDate的实际值,排查是否验证逻辑未生成错误:
console.log('dLExpDate error:', errors.dLExpDate, 'touched:', touched.dLExpDate);
5. 确保Formik验证配置正确
检查Formik的validateOnChange和validateOnBlur是否开启(默认均为true),如果手动修改过配置,需确保开启实时验证:
<Formik // ...其他配置 validateOnChange={true} validateOnBlur={true} > {/* ... */} </Formik>
内容的提问来源于stack exchange,提问作者ZunX
相关产品推荐
相关产品推荐

