react-final-form icon indicating copy to clipboard operation
react-final-form copied to clipboard

[Race condition] Multiple fields with async validators not updating field state in this user interaction

Open amized opened this issue 5 years ago • 2 comments

Are you submitting a bug report or a feature request?

Bug Report

What is the current behavior?

If I have two fields on the page that both use async validators, there is a scenario where my first validator function doesn't correctly update the form state. See this sandbox: https://codesandbox.io/s/gracious-payne-6ekgy

To replicate:

  1. Type something random into field 1
  2. While field 1 is validating and before the validation function resolves, focus onto field 2 and type "B" into it, which is the value that makes field 2 valid
  3. Notice that field 1's state remains stuck in {valid: true} and {validating: true}.
  4. Notice that my form state is {valid: true}, even though my async validator returns an error and should have updated the form state accordingly

What is the expected behavior?

I would have expected that when I perform the above interaction

  • my field 1 validator should have updated field 1s state to {invalid: true} and {validating: false} after returning an error
  • my form should be invalid

Sandbox Link

What's your environment?

React final form 6.4 Final form 4.19.1 Happens on my mac in both safari and chrome

Other information

amized avatar May 06 '20 23:05 amized

@erikras Just following up on this one, our sign up form is breaking when users move too quickly through our async validator fields

amized avatar Jun 23 '20 04:06 amized

This is still an issue, even with 1 async validator, which is triggered on each keystroke due to react-final-form having no debounce. The previous promises aren't handled correctly in order from what I can see while debugging.

What I see happening in our use-case is:

  • first character is entered
  • async validator triggers call, returning promise -- validating is set to true
  • second character is entered
  • async validator triggers call, returning promise -- validating is set to true
  • first promise returns an error -- (!) validating is set to false, as promise returns, but it's not checked if this was an "old" promise, which makes for buttons to become enabled etc.... so state of form/field is not correct anymore from this point on.
  • second promise returns an error -- Here state catches up off course, because this is the latest value. We are lucky to have implemented a "cut-off" for previous validation promises, otherwise, their order would mess this whole thing up even more.

So in short, final-form should mind the order of the promises, and not just setting validating to false when one resolves, as that is plain wrong.

dietergeerts avatar Jan 24 '22 11:01 dietergeerts