jaredpalmer / formik

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

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

Open andycarrell opened 4 years ago

andycarrell commented 4 years ago

πŸ› 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
omkar-joshi commented 4 years ago

I'd like to help with this

jaredpalmer commented 4 years ago

Go for it!

ks-amit commented 4 years ago

I'd like to help with this

Any progress on this?

omkar-joshi commented 4 years ago

Yeah. Putting up a PR in a couple of days

koredefashokun commented 4 years ago

@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.

btiwaree commented 4 years ago

Yeah. Putting up a PR in a couple of days

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

semopz commented 4 years ago

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

andycarrell commented 4 years ago

πŸ‘‹ 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:

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

bduffany commented 4 years ago

Here are a few options in my view:

Option 1:

Option 2:

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

rphlmr commented 4 years ago

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 πŸ˜‡

crhayes commented 4 years ago

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.

jktravis commented 3 years ago

Status?

vai0 commented 3 years ago

To add to this discussion, it seems the problem is because computing isValid dependent on dirty, but dirty is already set to true before the form finishes its first validation - this.state.errors is still empty at this point, computing isValid to true when it shouldn't be. https://github.com/formium/formik/blob/master/packages/formik/src/Formik.tsx#L940-L950

one possible solution is:

  1. add an additional validated flag (as a global, or part of the state, not sure) that gets set to true when runAllValidations resolves
  2. have the isValid computation depend on flag validated
    const isValid = dirty && validated ? ...

    if this makes sense, i can submit a PR

no-creative-name commented 3 years ago

@vai0 I like your approach. Are you still open for submitting this PR?

no-creative-name commented 3 years ago

@vai0 push πŸ€“

ctharings commented 1 year ago

Jan 6, 2020 😞

mitidiero commented 1 year ago

Any solutions or workarounds?