Mui DateTimePicker与react-hook-form错误行为不一致求助
问题
在使用react-hook-form控制的表单中集成Mui DateTimePicker组件,通过disablePast属性验证所选日期为未来日期时,出现错误状态未同步的问题:
- 选择明日日期→无错误(正常);改选昨日→出现disablePast错误(正常);再改选前日→无错误(异常)
- 选择两天前的日期→有错误(正常);改为昨日→无错误(异常);改为今日→有错误(异常,今日时间在当前时间之后)
相关代码如下:
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { useForm, useController } from "react-hook-form"; import { DateTimePicker } from "@mui/x-date-pickers/DateTimePicker"; // v6.0.4 import "dayjs/locale/en-gb"; const MyDateTimePicker = ({ name, control, error, setError }) => { const { field } = useController({ name, control }); const handleError = (reason) => { console.log(reason); setError(name, { type: "custom", message: reason }); }; return ( <DateTimePicker {...field} label="future date" disablePast onError={handleError} slotProps={{ textField: { error: !!error, helperText: error?.message } }} /> ); }; export default function App() { const { control, handleSubmit, setError, formState: { errors } } = useForm({ mode: "all", defaultValues: { datetime: null } }); const onSubmit = (data) => console.log(data); return ( <LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale="en-gb"> <div className="App"> <form onSubmit={handleSubmit(onSubmit)}> <MyDateTimePicker name="datetime" control={control} error={errors?.datetime} setError={setError} /> </form> </div> </LocalizationProvider> ); }
解决方案
问题核心在于仅依赖Mui的onError回调设置react-hook-form错误状态,但onError仅在错误状态发生变化时触发(如合法→非法、非法→合法的瞬间),连续选择同类型非法日期时不会重复触发,导致状态不同步。
正确做法是将日期验证逻辑统一交给react-hook-form,保留disablePast作为UI层面限制,具体修改如下:
修改后完整代码
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { useForm, useController } from "react-hook-form"; import { DateTimePicker } from "@mui/x-date-pickers/DateTimePicker"; // v6.0.4 import dayjs from "dayjs"; import "dayjs/locale/en-gb"; const MyDateTimePicker = ({ name, control, error }) => { const { field } = useController({ name, control, rules: { validate: (value) => { if (!value) return true; // 允许空值,若需必填可添加required规则 const isFuture = value.isAfter(dayjs()); return isFuture ? true : "请选择未来的日期时间"; } } }); return ( <DateTimePicker {...field} label="future date" disablePast slotProps={{ textField: { error: !!error, helperText: error?.message } }} /> ); }; export default function App() { const { control, handleSubmit, formState: { errors } } = useForm({ mode: "all", defaultValues: { datetime: null } }); const onSubmit = (data) => console.log(data); return ( <LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale="en-gb"> <div className="App"> <form onSubmit={handleSubmit(onSubmit)}> <MyDateTimePicker name="datetime" control={control} error={errors?.datetime} /> </form> </div> </LocalizationProvider> ); }
关键说明
- 利用
useController的rules.validate定义验证逻辑,每次字段值变化都会执行验证,确保错误状态实时同步 - 保留
disablePast作为UI层面的禁用限制,避免用户选择过去日期,最终验证逻辑由react-hook-form控制,保证状态一致性 - 若需设置必填,可在
rules中添加required: "此字段不能为空"规则
内容的提问来源于stack exchange,提问作者kougami
相关产品推荐
相关产品推荐

