Why does Formik validate EVERY input including pristines when a single input onChange is fired?

Viewed 1736

I'm really trying to wrap my head around why this is a design choice and how it's not more of an issue.

I have a form that has a number of inputs on it, and when I start typing in any of the fields the whole form is validated as per my validate function, causing every validation error message to be rendered onto my form.

The form isn't even doing anything magical either, I'm literally just taking in basic text input and validating if the values are empty or not. Yet when I do that, Formik thinks it's a great idea to validate EVERY field, including my pristine ones that are yet to be touched.

Can someone please explain to my how I can change this behaviour so that only the form currently firing onChange events is validated?

I've tried using the form's touched object to check which are yet to be touched and only validate the touched ones, but that produces more problems, especially when trying to submit the form.

validateOnChange and validateOnBlur don't help either, they just turn off the validation

Again, why is this the default behaviour. Who would ever want to validate their entire form at once based on onChange events?

I've even tried to do field-level validation using instead, and even that produces the same behaviour? I'm genuinely at a loss as to how anyone can produce working forms with this. Obviously people do, so if someone can explain how to do this on a field by field basis I'd very much appreciate it.

  const formik = useFormik({
    initialValues: {
      positionTitle: "",
      experienceRequired: ""
    },
    onSubmit: (values) => {
      console.log("Form output: ", JSON.stringify(values));
      console.log("Errors: ", formik.errors);
    },
    isInitialValid: false,
    validate: validate
    validateOnMount: false,
    validateOnChange: false,
    validateOnBlur: false
  });

<FormikProvider value={formik}>
    <form onSubmit={formik.handleSubmit} className="flex flex-col mt-4">

        <Field
        as="input"
        validate={validateBasicRequired}
        name="positionTitle"
        onChange={formik.handleChange}
        value={formik.values.positionTitle}
        ></Field>
        {formik.errors.positionTitle &&
        formik.errors.positionTitle === "Required" && (
            <BasicValidationError message="Required field."></BasicValidationError>
        )}

        <Select
        name="experienceRequired"
        onChange={handleSelectOnChange}
        options={getMultiSelectOptions(experienceValues)}
        ></Select>
        {formik.errors.experienceRequired &&
        formik.errors.experienceRequired === "Required" && (
            <BasicValidationError message="Required field."></BasicValidationError>
        )}
    </form>
</FormikProvider>

This is the validation function I was using before field-level

  const validate = (values: PostJobForm) => {
    const errors: any = {
      compensation: {},
    };

    if (!values.positionTitle) {
      errors.positionTitle = "Required";
    }

    if (!values.experienceRequired) {
      errors.experienceRequired = "Required";
    }

    return errors;
  };
0 Answers
Related