jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.88k stars 2.79k forks source link

Synchronous validation with Yup #2405

Open vvatikiotis opened 4 years ago

vvatikiotis commented 4 years ago

❓Question

Seriously, for immediate help, just ask your question on the #formik channel on Reactiflux.

I apologise for this question, however I had no luck on Reactiflux (so far).

Reproducible example

https://codesandbox.io/s/still-sun-zi4kt

Environment

Software Version(s)
Formik 2.1.4
Yup 0.28.3
React 16.13.1
TypeScript 3.8.3
Browser Chrome 80.0.3987.149
npm/Yarn Yarn 1.22.4
Operating System MacOS 10.14.6

So I have the following bare minimum one field form and I use Yup for validation. What I need is a way to get values and errors change synchronously. The following should (?) work but it doesn't:

const schema = yup.object({
  username: yup.string().required('this is required'),
});

<Formik
  initialValues={{username: '' }}
  initialErrors={{ username: 'Not filled' }}
  validate={values => {
    try {
      // validateYupSchema(values, schema, true); // doesn't work
      schema.validateSync(values);
    } catch (err) { return yupToFormErrors(err) }

    return {};
  }}
>
  {({ values, errors }) => {
    return (
      <Form>
        <Field name="username">
          {({ field, form, meta }) =>  <input label="Username" {...field} />}
        </Field>
      </Form>
    )
  }
</Formik>

In this example, when the field is filled, values and errors change asynchronously, i.e. values change and errors change after next render. Is there a way to 'sync' values and errors? Yup's .validateSync seemed like a good candidate.

StudioSpindle commented 4 years ago

Is'nt validateSync is a method of Yup, not of Formik?

Formik will check which type (async, sync) yup validation is used in the validateYupSchema.

And I guess the culprit is this promise in the runValidationSchema.

arcticmatt commented 3 years ago

validateSync is a method of Yup, but Formik provides no way to call it. Formik defines the validateYupSchema function, which takes in a flag controlling sync/async. However, that function is only ever called with sync = false.

This makes using Yup pretty annoying, because values and errors can get out of sync. So for example, if you use isValid to determine whether to disable a button, the button may "flicker" when you change your form because isValid is not consistent with validationSchema.isValidSync(values).

tpetillot commented 2 years ago

We're having the same problem. After a consecutive call of setFieldTouched then field prop onChange, two async validation are engaged.

In our case onChange values trigger a shorter validation in the yup schema, which led onChange validation result to be override by setFieldTouched validation result that ends later (with values that are out of sync).

Errors kept should always come from the latest validation call, not latest validation resolvation.