如何结合Yup校验使用MUI X DateTimePicker并限制起止日期范围
问题描述
当前使用React Hook Form结合MUI DateTimePicker实现起止日期选择,必填校验已生效,但用户仍可选择结束日期早于开始日期,需要限制该情况,同时必须保持日期提交格式为UTC。尝试过改用TextField、普通DatePicker及Dayjs均未解决问题。
现有代码
import { useForm, Controller } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import { DateTimePicker } from "@mui/x-date-pickers";
const schema = Yup.object({ startDate: Yup.date().required("startDate is required"), endDate: Yup.date().required("endDate is required"), });
const { register, control, formState: { errors }, handleSubmit, reset, watch, } = useForm({ defaultValues: { startDate: "", endDate: "", }, mode: "all", resolver: yupResolver(schema), });
const onSubmit = (data: any) => { data.startDate = new Date(data.startDate).toISOString(); data.endDate = new Date(data.endDate).toISOString(); };
<div className="grid grid-cols-4 ml-10 mr-56"> <div> <Controller name="startDate" control={control} render={({ field: { onChange, value } }) => ( <DateTimePicker disablePast id="startDate" label=" Start Date" placeholder="Start Date" value={value} onChange={onChange} renderInput={(params) => <TextField {...params} />} /> )} /> </div> <div> <Controller name="endDate" control={control} render={({ field: { onChange, value } }) => ( <DateTimePicker disablePast label=" End Date" id="endDate" placeholder="End Date" value={value} onChange={onChange} renderInput={(params) => <TextField {...params} />} /> )} /> </div> </div>
解决方案
可以从校验逻辑和组件交互限制两方面入手,同时保留UTC格式:
1. 用Yup添加日期比较校验
修改Yup schema,让结束日期必须晚于开始日期,同时基于UTC时间比较避免时区差异:
const schema = Yup.object({ startDate: Yup.date().required("startDate is required"), endDate: Yup.date() .required("endDate is required") .test( "is-after-start", "End date must be after start date", function(value) { const { startDate } = this.parent; if (!startDate || !value) return true; // 空值交给required规则处理 // 转换为UTC时间戳比较,消除时区影响 const startUTC = new Date(startDate).setHours(0, 0, 0, 0); const endUTC = new Date(value).setHours(0, 0, 0, 0); return endUTC > startUTC; } ), });
2. 在DateTimePicker中添加交互限制
通过watch监听起始日期,给结束日期选择器设置minDate,让用户无法选择早于起始日期的选项:
// 监听起始日期的实时值 const watchedStartDate = watch("startDate"); // 修改结束日期的Controller渲染逻辑 <Controller name="endDate" control={control} render={({ field: { onChange, value } }) => ( <DateTimePicker disablePast label=" End Date" id="endDate" placeholder="End Date" value={value} onChange={onChange} // 设置最小可选日期为已选的起始日期 minDate={watchedStartDate ? new Date(watchedStartDate) : null} // 绑定错误提示 renderInput={(params) => <TextField {...params} error={!!errors.endDate} helperText={errors.endDate?.message} />} /> )} />
3. 保留UTC格式
你当前onSubmit方法中把日期转为ISO字符串的逻辑无需修改,ISO字符串本身就是UTC标准格式,能满足需求。
这种方案既通过组件交互限制用户的错误选择,又通过校验逻辑在提交前做二次验证,双重保障解决问题。
内容的提问来源于stack exchange,提问作者MR.T
相关产品推荐
相关产品推荐

