Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling errors from api with Formik

I am catching errors from api and showing them in form, and that is working fine. But the problem is when I change one field in form all errors disappear. For form I am using Formik and for validation Yup.

const handleSubmit = (values, {setSubmitting,  setFieldError, setStatus}) => {
    someApiCall(values)
        .then(
            () => {

            },
            (error) => {
                // example of setting error
                setFieldError('email', 'email is already used');
            })
        .finally(() => {
            setSubmitting(false)
        });
};

I tried with adding third parametar false to setFieldError, but nothing changed.

like image 272
bobby Avatar asked Jun 28 '19 15:06

bobby


People also ask

How do you handle errors in Formik?

The way that Formik handles errors is that the returned error structure should map an error message to same structure as your values. In our case we have a single level object with a firstName key. So if our value below is set like this, then our error should map accordingly.

What is handleChange in Formik?

Formik has its own handleChange method that you can use to update the state with user inputs, there is no need to implement your own handleChange method. The handleChange method updates the form values based on the input's name attribute that was changed.

How does Formik touch work?

Like errors and values , Formik keeps track of which fields have been visited. It stores this information in an object called touched that also mirrors the shape of values / initialValues . The keys of touched are the field names, and the values of touched are booleans true / false .


2 Answers

Here's my working example: https://codesandbox.io/s/formik-example-dynamic-server-rendered-values-1uv4l

There's a callback validate available in Formik: https://jaredpalmer.com/formik/docs/api/formik#validate-values-values-formikerrors-values-promise-any using which you can probably try to do something like below.

I initiated emailsAlreadyInUse with empty array and then in your API call once error gets returned then add that user to the array and once user uses the same email again and tried to validate, although it will pass Yup validation but it will be caught in validate callback which I believe runs after Yup validation (though I could be wrong but in your case doesn't matter).

const emailsAlreadyInUse= [];
const handleSubmit = (values, {
  setSubmitting,
  setFieldError,
  setStatus
}) => {
  someApiCall(values)
    .then(
      () => {
        // Do something
        // possibly reset emailsAlreadyInUse if needed unless component is going to be unmounted.
      },
      (error) => {
        // example of setting error
        setFieldError('email', 'email is already used');
        // Assuming error object you receive has data object that has email property
        emailsAlreadyInUse.push(error.data.email);
      })
    .finally(() => {
      setSubmitting(false)
    });
};

<Formik
...
...
validate = {
  values => {
    let errors = {};
    if (emailsAlreadyInUse.includes(values.email)) {
      errors.email = 'email is already used';
    }
    return errors;
  }
}
/>
like image 130
Rikin Avatar answered Oct 18 '22 19:10

Rikin


I found simplier method to make API validation errors always visible than using validate method. You can set validateOnBlur and validateOnChange on your form to false. It will cause validation only on submit and errors returned from API will remain after changing field value.

Usage:

<Formik
        initialValues={initialValues}
        onSubmit={handleSubmit}
        validateOnBlur={false}
        validateOnChange={false}
      >
...form fields...
</Formik>
like image 2
Michał Zalewski Avatar answered Oct 18 '22 20:10

Michał Zalewski