formik icon indicating copy to clipboard operation
formik copied to clipboard

[v2] isValid=true on mount, even though initialValues are invalid and validateOnMount=true

Open martaver opened this issue 4 years ago • 48 comments

🐛 Bug report

Current Behavior

isValid is true once the form mounts, even though the validationSchema invalidates initialValues and the form is untouched.

Expected behavior

isValid prop to reflect the actual validity of the form at all times. Due to initialErrors, validating on mount automatically may be undesirable, which is understandable. So in this case, explicitly setting validateOnMount=true should definitely ensure isValid prop's value on mount is correct.

Reproducible example

Using Formik 2.0.3, an invalid form's isValid prop is true on mount. validateOnMount props doesn't seem to make a difference.

https://codesandbox.io/s/formik-example-zehlg

Suggested solution(s)

  • default isValid to false, as a start, if no initialErrors are provided. Hard to imagine a form that's valid with initialValues, unless you're reloading old values.
  • ensure that validateOnMount=true runs validation against initialValues during mount, so that isValid's initial value is correct.

Additional context

N/A

Your environment

Software Version(s)
Formik 2.0.3
React 16.11.0
TypeScript 3.6.4
Browser Chrome 77.0.3865.120
npm/Yarn yarn 1.19.0
Operating System macos 10.14.6 (18G103)

martaver avatar Oct 29 '19 09:10 martaver

I'm running into this issue too. I have validateOnMount set but I don't see any of my Field validation functions running and isValid is true.

nperrier avatar Oct 29 '19 20:10 nperrier

I don't see where in the source code that validationOnMount is referenced:

https://github.com/jaredpalmer/formik/search?q=validateOnMount&unscoped_q=validateOnMount

It looks like it was never implemented? If that's the case, remove it from the docs.

nperrier avatar Oct 29 '19 20:10 nperrier

I too had problems with validateOnMount and noticed this: https://github.com/jaredpalmer/formik/blob/master/src/Formik.tsx#L350

As a workaround, I have this hook in my form to do the validation on mount:

useEffect(() => {
  (() => validateForm())();
}, []);

Which is basically what Formik would do under the hood.

hannupekka avatar Oct 30 '19 05:10 hannupekka

Does anyone know why validateOnMount was commented out and when it will be fully implemented?

jonathanwelton avatar Oct 30 '19 14:10 jonathanwelton

This is fixed in release 2.0.4.

clintonb avatar Nov 18 '19 03:11 clintonb

I don't think is fixed. I forked @Martaver sandbox and changed to version 2.0.4

https://codesandbox.io/s/formik-example-jwwu5

I console.log isValid and initial is always true, then after first rerender it becomes false

igor-krupa avatar Feb 21 '20 11:02 igor-krupa

@igorkrup yeah... I ended up using hannupekka's useEffect workaround.

mwmcode avatar Feb 21 '20 12:02 mwmcode

I usually don't like to bump an issue but this is still happening despite being "stale." And I guess commenting will remove the stale tag.

djensen47 avatar Apr 27 '20 16:04 djensen47

@hannupekka @mustafawm How did you get the validateForm outside of the context of the <Formik> component? Or are you using useFormik?

djensen47 avatar Apr 27 '20 16:04 djensen47

Any update on this? It seems like I can use dirty as a workaround, but still the issue exists. Initially isValid === true and isValidating === false. Sometimes on new page it is not visible, but when navigating between tabs it can be seen

tar-aldev avatar May 07 '20 06:05 tar-aldev

When specifying validateOnMount={true}, isValidating is false on first render. It seems like isValidating should be true in this case.

crhayes avatar May 07 '20 23:05 crhayes

+1

hmac2222 avatar May 08 '20 21:05 hmac2222

I wouldn't be against setting isValidating to true on initial render when validateOnMount is true. It's technically a lie, so we'd have to make sure that if validation never runs (is that possible?) it would revert back to false at some point.

johnrom avatar May 08 '20 21:05 johnrom

+1 I suggest isValid should be false until at least one validation has been executed.

gael33 avatar Jun 03 '20 07:06 gael33

+1

TomBerriot avatar Jun 11 '20 14:06 TomBerriot

I suggest isValid should be false until at least one validation has been executed.

An issue I have with this approach is that it's perfectly reasonable to pre-fill a form with valid data and specify validateOnMount={false}. In that case I would expect isValid to be true.

Forgive me if you meant that it should only behave this way when validateOnMount={true}. The intent was not clear from your comment.

crhayes avatar Jun 11 '20 15:06 crhayes

When specifying validateOnMount={true}, isValidating is false on first render. It seems like isValidating should be true in this case.

Specifying validadeOnMount={true} works for what I need, thanks.

parzivalClaus avatar Jun 26 '20 13:06 parzivalClaus

validadeOnMount: true not working with useFormik. Any updates on this?

ghost avatar Jul 29 '20 13:07 ghost

Same issue here. A hacky workout around for me right now is isInitialValid={false} which isn't always true. Would be better if validateOnMount={true} worked.

charleshimmer avatar Jul 29 '20 14:07 charleshimmer

I also have the same issue, does anybody have a clue where the problems lies?

TNAJanssen avatar Aug 10 '20 20:08 TNAJanssen

I think the difficulty with providing a comprehensive solution to this problem is that 'validation' can include custom validators that are async and can make requests to check validity. If we are re-evaluating validation state immediately on init, then potentially it would run all of those requests again which is undesirable.

I think the only viable solution to a problem like this is to capture 'validation state' and load it simultaneously with initial values, and this is non-trivial.

I'm not certain, but that's probably the reason there hasn't been a 'quick fix' for this. @jaredpalmer is this the case?

martaver avatar Aug 11 '20 08:08 martaver

Well summarized. This is the problem. GitHub [email protected] wrote: “I think the difficulty with providing a comprehensive solution to this problem is that 'validation' can include custom validators that are async and can make requests to check validity. If we are re-evaluating validation state immediately on init, then potentially it would run all of those requests again which is undesirable.

I think the only viable solution to a problem like this is to capture 'validation state' and load it simultaneously with initial values, and this is non-trivial.

I'm not certain, but that's probably the reason there hasn't been a 'quick fix' for this. @jaredpalmer is this the case?”

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

jaredpalmer avatar Aug 11 '20 09:08 jaredpalmer

So... its non-trivial... but can we do it anyway? :D

martaver avatar Aug 11 '20 10:08 martaver

i have same issue . but i solve this with some codes : i set isInitialValid to a state that have a same name (isInitialValid). and change this state just with schema.validate every time my defaultValues changed.

const [isInitialValid, setIsInitialValid] = useState(false);'

 useEffect(() => {
    schema
      .validate(defaultValues)
      .then((res) => setIsInitialValid(true))
      .catch((err) => setIsInitialValid(false));
  }, [defaultValues]);

  return ( 
<Formik
        initialValues={defaultValues}
        enableReinitialize
        isInitialValid={isInitialValid} 
        validationSchema={schema}
       >
//my fields 
</Formik>

mrlaseptima avatar Aug 25 '20 08:08 mrlaseptima

[email protected]

https://codesandbox.io/s/formik-example-forked-dgf5j?file=/index.js

C-E-Rios avatar Aug 25 '20 18:08 C-E-Rios

Looks like the fix is not available in [email protected].

Tried out 2.1.4 and it is working fine as expected with validateOnMount={true}

akhatriST avatar Sep 22 '20 14:09 akhatriST

I am usint 2.1.5 and validateOnMount={true} is not working.

mariusLionte123 avatar Sep 23 '20 08:09 mariusLionte123

as a new Formik user I just had to downgrade from 2.1.5 to 2.1.4 for validateOnMount={true} to actually work/fill the error object. Why was it removed in 2.1.5?

amazing tool by the way thank you for all of your work making this.

Jared-Dahlke avatar Sep 26 '20 02:09 Jared-Dahlke

I've done it by doing that:

const formRef = useRef<any>();

useEffect(() => {
    formRef?.current?.validateForm();
}, []);

<Formik
    innerRef={formRef}
    validationSchema={validation}
    initialValues={{password: ''}}
    validateOnMount
    onSubmit={(values, formikHelpers) => onSubmit(values, formikHelpers)}>
</Formik>

dommangetnicolas avatar Oct 07 '20 19:10 dommangetnicolas

When specifying isValid, you can get dirty as well and add it to your condition is_disabled={!dirty || isSubmitting || !isValid}

matin-deriv avatar Nov 26 '20 08:11 matin-deriv

best approach to set initial validation to false I found a prop called : isInitialValid. here is my code and my initial validation to set submit button disabled or not I used it in such a way? const formik = useFormik({ initialValues: { firstName: firstName, lastName: lastName }, validationSchema: Yup.object({ firstName: Yup.string() .max(15, 'Must be 15 characters or less') .required('Required'), lastName: Yup.string() .max(20, 'Must be 20 characters or less') .required('Required'), }), isInitialValid : false });

and my button : <Button disabled={!formik.isValid} onClick={() => nextHandler()} >

farzanfx avatar Dec 23 '20 13:12 farzanfx

best approach to set initial validation to false I found a prop called : isInitialValid. here is my code and my initial validation to set submit button disabled or not I used it in such a way? const formik = useFormik({ initialValues: { firstName: firstName, lastName: lastName }, validationSchema: Yup.object({ firstName: Yup.string() .max(15, 'Must be 15 characters or less') .required('Required'), lastName: Yup.string() .max(20, 'Must be 20 characters or less') .required('Required'), }), isInitialValid : false });

and my button : <Button disabled={!formik.isValid} onClick={() => nextHandler()} >

yes, this pretty much solves it (formik 2.2.5)

superamxpruebas avatar Jan 13 '21 19:01 superamxpruebas

For now that works for me too, but there's this warning: Warning: isInitialValid has been deprecated and will be removed in future versions of Formik. Please use initialErrors or validateOnMount instead.

joaopaulobdac avatar Jan 14 '21 14:01 joaopaulobdac

isInitialValid is now !empty(initialErrors) (though you can continue using isInitialValid for now), so you should be able to do initialErrors={{ manuallyIndicatingAn: "Error" }}, or just run your validate() function on initialValues, which we don't do within a Formik render because we cannot prove it to be render safe / it may be expensive or async for some users

const validationSchema = Yup.object({ 
  firstName: Yup.string() .max(15, 'Must be 15 characters or less') .required('Required'), 
  lastName: Yup.string() .max(20, 'Must be 20 characters or less') .required('Required'), 
});

const initialValues = {
  firstName: '',
  lastName: '',
};

const MyForm = () => (
  <Formik 
    initialValues={initialValues} 
    validationSchema={validationSchema} 
    isInitialValid={validationSchema.validateSync(initialValues) /* or whatever Yup's API looks like, also memoize this */}
  />
);

johnrom avatar Jan 14 '21 18:01 johnrom

This is the workaround I found since isValid is true when the form loads: isEmpty belongs to lodash lib.

disabled={!dirty || !isValid || !isEmpty(errors)}

flormasuyama avatar Feb 23 '21 15:02 flormasuyama

This is how I solved it: const InitialValidate = () => { const { values, submitForm, validateForm, dirty } = useFormikContext(); React.useEffect(() => dirty && (() => validateForm())(), [values, submitForm]); return null; };

Component: <InitialValidate />

Ideal because can be optionally used in a Stepped form.

laurensdacosta avatar Jun 24 '21 09:06 laurensdacosta

yikes

schester44 avatar Jul 08 '21 18:07 schester44

Seems it's been resolved in Formik 2.2.9

shinchannn avatar Aug 05 '22 01:08 shinchannn