Formik: validateOnMount: Initial value for is valid should be whether the initial values are valid, when validateOnMount is true

Created on 7 Jan 2020  路  12Comments  路  Source: formium/formik

馃悰 Bug report

Current Behavior

When validateOnMount is true, initial value for isValid is 'true', then validation occurs on initial values (which could set isValid to 'false').

Screenshot taken from reproducible example - see console for inconsistency - isValid has a different value, for the same form value (empty string in the example):

image

Expected behavior

The first render should return the result of validating the initial values for isValid.

Reproducible example

https://codesandbox.io/s/formik-codesandbox-template-kegrs

Additional context

Would this problem be solved by setting initial errors? I believe possibly, although that would require running validation manually, defeating the purpose of validateOnMount.

The example is a simplification - application code has a far more complex validation schema + more initial values.

Your environment

| Software | Version(s) |
| ---------------- | ---------- |
| Formik | 2.1.1 |
| React | 16.12.0 |
| TypeScript | - |
| Browser | Codesandbox? && Chrome |
| npm/Yarn | 6.13.4 |
| Operating System | MacOSX 10.15.2 |

Formik Validation in progress

Most helpful comment

Ultimately the state of isValid cannot be known until validation completes, unless it is explicitly provided (which defeats the purpose of validateOnMount).

Where I have experienced this issue, and likely where many others have, is in trying to control enabled/disabled state of a submit button.

Typically the button would be disabled while validations are running. The logic would therefore be disabled={isValidating || !isValid}.

The problem is that isValidating is false on initial render even when validateOnMount is set to true. This seems counterintuitive. Having isValidating default to true when validateOnMount is true would likely allow most of us to work around this issue.

All 12 comments

I'd like to help with this

Go for it!

I'd like to help with this

Any progress on this?

Yeah. Putting up a PR in a couple of days

@omkar-joshi is there any progress on this? If you're still working on the PR, I would really appreciate if you could explain any workarounds for this issue at this time. Also, is there any way to prevent Formik from setting errors after running validateOnMount. I would like to set the isValid value, but not have errors on the fields. Thanks for your anticipated help.

Yeah. Putting up a PR in a couple of days

Hi @omkar-joshi any update on this? appreciate your contribution towards OSS.

Is it just a case of using validateFormWithHighPriority instead of validateFormWithLowPriority? https://github.com/jaredpalmer/formik/blob/f117c04738ed218b5eb8916d7189e0849962d50d/packages/formik/src/Formik.tsx#L366-L370

馃憢 Hi @semopz I've been looking into this a bit this weekend, and I don't think high/low priority will fix this issue unfortunately. Both validate form functions (withLow... / withHigh...) call runAllValidations which runs asynchronously - so from mount until that promise resolves, isValid will be true. This can cause an unideal user experience, specifically if isValid is used to drive form appearance, for example disabling the submit button. As a consumer of formik, I need to know what to render while validation on mount is running 馃

Some possible solutions (in user-land or in the library) I can think of are:

  • Resolve validation to initialErrors, then render
  • Bring back (from deprecation) isInitialValid - to set isValid whilst validation on mount is running
  • Somehow run validation synchronously 馃槙
  • Set isValidating to true initially, then use this value to determine what to render. (I've coded this here to show how)

Not really sure how to proceed with this, I understand to an extent why isInitialValid was deprecated, but also think removing it isn't serving us well in this scenario.

Validate form with low priority:

https://github.com/jaredpalmer/formik/blob/f117c04738ed218b5eb8916d7189e0849962d50d/packages/formik/src/Formik.tsx#L327-L331

Login button flash (enabled => disabled)

Kapture 2020-03-01 at 21 31 16

Here are a few options in my view:

Option 1:

  • If validation can be run synchronously, then Formik should synchronously validate before the first render. This at least fixes the flashing issue for forms that validate synchronously (pure speculation here, but I'd guess the vast majority of forms probably have synchronous validation, so this should fix the bug for "the 80%").
  • If validation _cannot_ be run synchronously, then force the state to be invalid until the first validation is complete. However, this does not fix the "flashing" issue because it may be the case that the form is computed to be valid after all, and then it flashes from invalid -> valid.

Option 2:

  • Un-deprecate isInitialValid and only issue a warning if the user uses _more than one_ of { isInitialValid, validateOnMount, and initialErrors}, which could result in conflicting validation states & thus render flashing. IMO this is the simplest and best option. But it does not account for cases where we legitimately need to do an async call in order to compute whether the initial state is valid. (But really, do these cases even exist in the wild? I can't think of a real-world example where an async-validated form doesn't know its initial validation state on initial render. In fact it seems like in "80%" of cases, the initial state is invalid, so it seems like isInitialValid should have been defaulting to false this whole time!)

If people think that Option 2 makes sense, I can send a PR.

I stick on option 2 and use isInitialValid. It fits my needs, it's a simple props to disable a submit button before user completes fields 馃槆

Ultimately the state of isValid cannot be known until validation completes, unless it is explicitly provided (which defeats the purpose of validateOnMount).

Where I have experienced this issue, and likely where many others have, is in trying to control enabled/disabled state of a submit button.

Typically the button would be disabled while validations are running. The logic would therefore be disabled={isValidating || !isValid}.

The problem is that isValidating is false on initial render even when validateOnMount is set to true. This seems counterintuitive. Having isValidating default to true when validateOnMount is true would likely allow most of us to work around this issue.

Status?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaredpalmer picture jaredpalmer  路  3Comments

emartini picture emartini  路  3Comments

giulioambrogi picture giulioambrogi  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments

sibelius picture sibelius  路  3Comments