DatePicker needing 2 clicks to update error, Formik and Yup

36 Views Asked by At

I have this Material UI DatePicker:


                    <Grid item xs={12}>
                        <LocalizationProvider dateAdapter={AdapterDayjs}>
                            <DatePicker 
                                label="Date of birth" 
                                format="DD/MM/YYYY" 
                                value = {values.dob}

                                sx={{ width: '50%' }}
                                slotProps={{
                                    textField: {
                                    id: 'dob',
                                    helperText: touched.dob ? errors.dob : "",
                                    error: touched.dob && Boolean(errors.dob),
                                    },
                                    }}
                                    onChange={(value) => { 
                                        setFieldValue('dob', value ? dayjs(value).toDate() : null);
                                        setFieldTouched('dob', true); 
                                    }}
                                />
                        </LocalizationProvider>
                    </Grid>

The problem I have is that my DatePicker only works at the second time.

It says required at the first time instead of saying Date of birth cannot be in the future then at the second time it says Date of birth cannot be in the future.

I always need 2 clicks to change it, if it says Date of birth cannot be in the future and then I change it to yesterday it will still say "Date of birth cannot be in the future", I need to click something else per example the textfield name and click somewhere else and it will update.

If someone can help me it would be great.

Formik:

    const { values, errors, touched, handleBlur, handleChange, handleSubmit, setFieldValue, setFieldTouched } = useFormik({
        initialValues: {
            name: "",
            dob: null,
            email: "",
        },   
        validationSchema: formSchema,
        
    });

Yup:

export const formSchema = yup.object().shape({
    name: yup.string().matches(nameRules, 'Please enter a valid name').max(40).required("Required"),
    dob: yup.date().max(new Date(), 'Date of birth cannot be in the future').required('Required'), 
    email: yup.string().email("Please enter a valid email").required("Required"),
});

I found out that what is making it having to be clicked 2 times to change is the setFieldTouched('dob', true); but if I remove it then I will lose my helperText.

I am expecting for it to change with one click.

2

There are 2 best solutions below

0
Miguel Ângelo Freitas On BEST ANSWER

I just found out why, the setFieldTouched needs to come first.

onChange={(value) => { 
  setFieldTouched('dob', true);
  setFieldValue('dob', value ? dayjs(value).toDate() : null);
}}

instead of:

onChange={(value) => { 
  setFieldValue('dob', value ? dayjs(value).toDate() : null);
  setFieldTouched('dob', true);
}}
1
Yazan Ali On

It looks like the issue is related to the order in which Formik's setFieldValue and setFieldTouched are being called in your DatePicker's onChange handler. The setFieldTouched is being called after setFieldValue, and Formik might not be updating the touched state in time for the first render. To resolve this issue, you can try updating the order of these calls. Move the setFieldTouched before setFieldValue

If the issue persists, you can also try using validateOnChange and validateOnBlur options in the useFormik configuration to control when Formik runs validation.

For example:

const {
  values,
  errors,
  touched,
  handleBlur,
  handleChange,
  handleSubmit,
  setFieldValue,
  setFieldTouched
} = useFormik({
  initialValues: { name: "", dob: null, email: "" },
  validationSchema: formSchema,
  validateOnChange: true, // Set this option to true
  validateOnBlur: true // Set this option to true
});