Search code examples
javascriptreactjsmaterial-uidatepickerreact-hook-form

Inconsistent error behaviour with Mui DateTimePicker and react-hook-form


I have a DateTimePicker component that I'm trying to use in a form controlled by react-hook-form, the validation is really simple, using the disablePast prop on the DateTimePicker to ensure that the date selected is in the future.

The issue is that, for reasons unknown, the error does not persist through the value being changed, even if the new value is also invalid. For example:

  1. Select tomorrow's date - no error (as it should be)
  2. Change the selected date to yesterday - disablePast error (as it should be)
  3. Change the selected date to the day before that - no error, but there should be

It also exhibits a similar behaviour when going back up, e.g:

  1. Enter in a date for two days ago - error (as it should be)
  2. Increase the date by one, so the value is yesterday - no error, but there should be
  3. Increase the date by one again, so the value is today - error, but there shouldn't be

All of this is, of course, assuming that the time selected is after the current time, so "today" being selected is definitely not in the past.

I have a feeling that the 'error state' of the Mui component and react-hook-form are not in sync with each other, but I'm not sure how to fix it.

I've put together a codesandbox here, where the issue can be seen:

https://codesandbox.io/s/reverent-pare-yebckz?file=/src/App.js

And my code is also included here:

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>
  );
}

I feel like I'm losing my mind a little bit with this one, so any assistance would be greatly appreciated. Thank you

edit: It seems like setError is perhaps the problem. How, then, can I connect Mui's validation to react-hook-form's validation so they work together?


Solution

  • Fixed it by ditching setError entirely and writing my own validation as part of react-hook-form's rules.

    Working example: https://codesandbox.io/s/eloquent-kowalevski-0qdnyt?file=/src/App.js