如何在TimePicker/DesktopDatePicker无效时禁用按钮?
解决MUI TimePicker/DesktopDatePicker无效输入时按钮仍可点击的问题
方案一:手动校验值并管理错误状态
直接通过监听Picker的onChange事件,每次值变化时校验是否为有效的Date对象,同时保留onError捕获组件抛出的错误,双向更新错误状态:
import { useState } from 'react'; import { Button, FormControl, FormHelperText, TextField } from '@mui/material'; import { TimePicker, DesktopDatePicker } from '@mui/x-date-pickers'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; export default function PickerForm() { const [dateValue, setDateValue] = useState(null); const [timeValue, setTimeValue] = useState(null); const [hasError, setHasError] = useState(false); // 统一校验日期和时间的有效性 const checkValidity = () => { const isDateValid = dateValue instanceof Date && !isNaN(dateValue); const isTimeValid = timeValue instanceof Date && !isNaN(timeValue); setHasError(!(isDateValid && isTimeValid)); }; const handleDateChange = (newValue) => { setDateValue(newValue); checkValidity(); }; const handleTimeChange = (newValue) => { setTimeValue(newValue); checkValidity(); }; // 捕获组件抛出的错误,标记状态 const handleError = () => { setHasError(true); }; return ( <LocalizationProvider dateAdapter={AdapterDateFns}> <FormControl error={hasError} sx={{ m: 2 }}> <DesktopDatePicker label="选择日期" value={dateValue} onChange={handleDateChange} onError={handleError} renderInput={(params) => <TextField {...params} />} /> <TimePicker label="选择时间" value={timeValue} onChange={handleTimeChange} onError={handleError} renderInput={(params) => <TextField {...params} sx={{ mt: 2 }} />} /> {hasError && <FormHelperText>日期或时间输入无效,请检查</FormHelperText>} <Button variant="contained" disabled={hasError} sx={{ mt: 2 }} onClick={() => console.log('执行保存逻辑')} > 保存 </Button> </FormControl> </LocalizationProvider> ); }
这个方法的核心是每次值变更时主动校验,不管用户是手动输入错误还是通过选择器修改,都能实时更新错误状态,解决了onError只触发错误出现、不触发错误消除的问题。
方案二:用react-hook-form自动管理表单校验
如果是复杂表单场景,推荐用react-hook-form集成,它会自动处理字段校验和状态更新,无需手动维护error变量:
import { useForm, Controller } from 'react-hook-form'; import { Button, TextField } from '@mui/material'; import { TimePicker, DesktopDatePicker } from '@mui/x-date-pickers'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; export default function PickerWithForm() { const { control, formState: { isValid }, handleSubmit } = useForm({ mode: 'onChange', // 实时触发校验 defaultValues: { date: null, time: null } }); const onSubmit = (formData) => { console.log('保存数据:', formData); // 这里写你的保存逻辑 }; return ( <LocalizationProvider dateAdapter={AdapterDateFns}> <form onSubmit={handleSubmit(onSubmit)} style={{ margin: 20 }}> <Controller name="date" control={control} rules={{ required: '日期不能为空', validate: (val) => val instanceof Date && !isNaN(val) || '请输入有效的日期' }} render={({ field, fieldState: { error } }) => ( <DesktopDatePicker label="选择日期" value={field.value} onChange={field.onChange} renderInput={(params) => ( <TextField {...params} error={!!error} helperText={error?.message} /> )} /> )} /> <Controller name="time" control={control} rules={{ required: '时间不能为空', validate: (val) => val instanceof Date && !isNaN(val) || '请输入有效的时间' }} render={({ field, fieldState: { error } }) => ( <TimePicker label="选择时间" value={field.value} onChange={field.onChange} renderInput={(params) => ( <TextField {...params} error={!!error} helperText={error?.message} sx={{ mt: 2 }} /> )} /> )} /> <Button variant="contained" type="submit" disabled={!isValid} sx={{ mt: 2 }} > 保存 </Button> </form> </LocalizationProvider> ); }
通过Controller把Picker注册到表单,设置校验规则后,isValid状态会自动根据所有字段的校验结果更新,按钮的disabled直接绑定!isValid,错误消除时按钮会自动恢复可用,完全不用手动处理状态重置。
内容的提问来源于stack exchange,提问作者Happy1234
相关产品推荐
相关产品推荐

