使用Material UI DatePicker结合Formik时遇TypeError: date.isBefore is not a function求助
解决Material UI DatePicker + Formik的「TypeError: date.isBefore is not a function」错误
错误根源
- 类型不匹配:使用
AdapterDayjs时,Material UI DatePicker要求value必须是dayjs对象,但你设置的初始值是原生new Date(),导致组件内部调用dayjs的isBefore方法时,因值为原生Date对象而报错(原生Date没有该方法)。 - onChange逻辑不兼容:Formik的
handleChange是为原生表单元素设计的,它期望接收Event对象并读取event.target.value,但DatePicker的onChange直接返回dayjs日期对象,直接使用会导致Formik无法正确更新values。
修复步骤
1. 导入dayjs依赖
取消注释dayjs的导入语句,因为AdapterDayjs依赖dayjs库:
import dayjs from 'dayjs';
2. 统一日期值类型
将Formik的initialValues中dob改为dayjs(),确保和DatePicker期望的类型一致:
initialValues={{ userName: "", dob: dayjs() }}
3. 适配DatePicker的onChange逻辑
使用Formik提供的setFieldValue方法手动更新dob字段,替代原生的handleChange:
<DatePicker label="Date of birth" value={values.dob} onChange={(newValue) => setFieldValue("dob", newValue)} onBlur={handleBlur} name="dob" error={Boolean(touched.dob) && Boolean(errors.dob)} helperText={touched.dob && errors.dob} />
4. 调整Yup验证规则
改用yup.mixed().test()验证dayjs对象的有效性,替代原有的yup.date():
const userSchema = yup.object().shape({ userName: yup.string().required("required"), dob: yup.mixed().test( "is-valid-date", "required", (value) => dayjs.isDayjs(value) && value.isValid() ) });
完整修复代码
import React from "react"; import { Formik } from "formik"; import { Box, Button, Paper, Stack, TextField, styled } from "@mui/material"; import { Lock } from "@mui/icons-material"; import * as yup from "yup"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import dayjs from 'dayjs'; const LoginPage = () => { const StyledPaper = styled(Paper)({ width: "500px", borderRadius: "10px", backgroundColor: "white", padding: "30px", position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)" }); const userSchema = yup.object().shape({ userName: yup.string().required("required"), dob: yup.mixed().test( "is-valid-date", "required", (value) => dayjs.isDayjs(value) && value.isValid() ) }); const handleFormSubmit = (values, onSubmitProps) => { // 如需转换为原生Date对象,可调用dayjs的toDate()方法 const dobAsNativeDate = values.dob.toDate(); console.log("表单值:", values); console.log("出生日期(原生Date):", dobAsNativeDate); }; return ( <Formik onSubmit={handleFormSubmit} initialValues={{ userName: "", dob: dayjs() }} validationSchema={userSchema} > {({ values, errors, touched, handleBlur, handleSubmit, setFieldValue }) => ( <form onSubmit={handleSubmit}> <StyledPaper elevation={3}> <Box sx={{ display: "flex", justifyContent: "center", alignItems: "center", margin: "10px" }} > <Lock color="primary" fontSize="large" /> </Box> <Stack direction="column" gap={2}> <TextField label="User Name" value={values.userName} onChange={handleChange} onBlur={handleBlur} name="userName" error={Boolean(touched.userName) && Boolean(errors.userName)} helperText={touched.userName && errors.userName} /> <LocalizationProvider dateAdapter={AdapterDayjs}> <DatePicker label="Date of birth" value={values.dob} onChange={(newValue) => setFieldValue("dob", newValue)} onBlur={handleBlur} name="dob" error={Boolean(touched.dob) && Boolean(errors.dob)} helperText={touched.dob && errors.dob} /> </LocalizationProvider> <Button variant="contained" type="submit"> Submit </Button> </Stack> </StyledPaper> </form> )} </Formik> ); }; export default LoginPage;
关键说明
- 所有与DatePicker交互的日期值必须保持为dayjs对象,避免类型转换错误。
- 使用
setFieldValue是Formik中手动更新字段值的标准方式,适合处理非原生表单组件的回调。 - 在提交表单时,可通过
dayjs.toDate()将dayjs对象转换为原生Date对象,方便后续业务处理。
内容的提问来源于stack exchange,提问作者Priyanka Chaurasia
相关产品推荐
相关产品推荐

