如何在提交预订后禁用Material UI日历中的已选日期
解决Material UI DateTimePicker禁用已预订日期的问题
我在React应用的表单中集成了Material UI Date & Time picker做预订系统,用户可以选择日期时间并提交姓名、邮箱。需求是提交后的日期时间存入数组,后续用户选到这些日期时,日历要禁用它们避免重复预订。尝试用shouldDisableDate方法但遇到瓶颈,代码如下:
import React, {useState } from "react"; import DateFnsUtils from '@date-io/date-fns'; import { DateTimePicker, MuiPickersUtilsProvider} from "@material-ui/pickers"; function Booking() { const [selectedDate, handleDateChange] = useState(new Date()); const [calendarData, setCalendardata] = useState([]); console.log(calendarData); console.log(selectedDate); let stringfySelectedDate = JSON.stringify(selectedDate); const onSubmitDate = (e) => { e.preventdefault(); // If the the array length is === to zero then add the first element if(calendarData.length === 0) { setCalendardata([...calendarData, stringfySelectedDate]); console.log("empty array"); } if(calendarData.includes(stringfySelectedDate)) { console.log("already exist"); return calendarData; } else { setCalendardata([...calendarData, JSON.stringify(selectedDate)]); } } return ( <> <MuiPickersUtilsProvider utils={DateFnsUtils}> <DateTimePicker label="Book" inputVariant="outlined" value={selectedDate} onChange={handleDateChange} shouldDisableDate={} disablePast showTodayButton clearable id="calendar" /> </MuiPickersUtilsProvider> <div className="col-12"> <div className="text-center"> <button onClick={onSubmitDate} className="nb butn light mt-30 full-width" > <span className="ls3 text-u">click</span> </button> </div> </div> </> ); } export default Booking;
问题分析与修复步骤
修正提交函数拼写错误
原代码里e.preventdefault()是小写的d,应该改为e.preventDefault(),否则阻止默认行为无效。优化日期存储格式
用JSON.stringify存储日期会带来时区、精度不一致的问题,建议把日期转成ISO标准字符串(比如selectedDate.toISOString())或者统一格式的时间字符串,保证对比时的准确性。实现
shouldDisableDate方法
这个方法接收一个date参数,我们需要把这个参数转成和存储的日期一致的格式,然后判断是否在已预订数组中,返回true就会禁用该日期。简化提交逻辑
原代码的判断逻辑冗余,不需要单独处理空数组的情况,直接判断当前选中的日期是否已存在,不存在就添加到数组。
修改后的完整代码
import React, { useState } from "react"; import DateFnsUtils from '@date-io/date-fns'; import { DateTimePicker, MuiPickersUtilsProvider} from "@material-ui/pickers"; function Booking() { const [selectedDate, handleDateChange] = useState(new Date()); const [bookedDates, setBookedDates] = useState([]); // 统一日期格式为ISO字符串,避免对比误差 const formatDate = (date) => date.toISOString(); const onSubmitDate = (e) => { e.preventDefault(); const formattedSelectedDate = formatDate(selectedDate); // 检查日期是否已预订,未预订则添加 if (!bookedDates.includes(formattedSelectedDate)) { setBookedDates([...bookedDates, formattedSelectedDate]); } else { console.log("该日期已被预订"); } }; // 实现禁用已预订日期的逻辑 const shouldDisableDate = (date) => { const formattedDate = formatDate(date); return bookedDates.includes(formattedDate); }; return ( <> <MuiPickersUtilsProvider utils={DateFnsUtils}> <DateTimePicker label="Book" inputVariant="outlined" value={selectedDate} onChange={handleDateChange} shouldDisableDate={shouldDisableDate} disablePast showTodayButton clearable id="calendar" /> </MuiPickersUtilsProvider> <div className="col-12"> <div className="text-center"> <button onClick={onSubmitDate} className="nb butn light mt-30 full-width" > <span className="ls3 text-u">提交预订</span> </button> </div> </div> </> ); } export default Booking;
关键说明
formatDate函数统一日期格式,避免因时区或日期对象的差异导致对比失败shouldDisableDate方法会在日历渲染每个日期时调用,返回true就会禁用该日期- 提交逻辑简化后,只需要判断日期是否已存在,不存在就添加到已预订数组
内容的提问来源于stack exchange,提问作者David Jay
相关产品推荐
相关产品推荐

