formik: Incorrect validation if setFieldTouched is executed immediatly after setFieldValue
🐛 Bug report
Current Behavior
There is an issue with calling setFieldTouched
, setTouched
, or onBlur
immediatly after updating the form values.
Due to using state.values here and here, any state change has to be commited (re-rendered) before a call to setFieldTouched, setTouched, or onBlur, otherwise the previous values will be validated instead.
This looks to be the same issue as #106, and is likely a regression that occured during the v2 hooks rewrite.
Expected behavior
Calling setFieldTouched
immediatly after setFieldValue
should not result in incorrect validation.
Reproducible example
https://codesandbox.io/s/formik-codesandbox-template-htdsu?file=/index.js
- @material-ui/pickers calls
onChange
andonAccept
synchrounsly when selecting a date.onBlur
is only called when the input itself is blurred. - react-datepicker calls
onChange
andonSelect
synchrounsly when selecting a date.onBlur
is only called when the input itself is blurred.
Suggested solution(s)
Additional context
https://github.com/jaredpalmer/formik/issues/2432 https://github.com/jaredpalmer/formik/issues/106
Fix in v1: https://github.com/jaredpalmer/formik/pull/176
Your environment
Software | Version(s) |
---|---|
Formik | 2.1.4 |
React | 16.13.1 |
TypeScript | |
Browser | |
npm/Yarn | |
Operating System |
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 30
- Comments: 16 (1 by maintainers)
For those that come across this issue you can also temporarily solve this race condition this way:
Getting the same issue when using
formik-material-ui-pickers
. Found a temporary workaround which seems to work so far -setFieldTouched(fieldName, true, false)
in theonAccept
callback. The 3rd parameterfalse
makes formik skip validation on that call, so instead it would get the validation result from the earliersetFieldValue
call (which, presumably, has the correct values).As @KristijanKanalas mentioned,
setFieldValue
will return a promise so his workaround fixes it. Although, for example in case you’d like async/await style:They either do actual same result
Was trying to track down this issue for hours in my app. Nice find @skoging… hopefully this gets addressed soon.
You would think not if you look at the types it’s defined as
setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void;
but in the actual implementation it does in fact return a promise. A simple console.log confirms it, and that’s why this solution works. To be fair it might be easily broken in the future if they change the implementation so I don’t wholeheartedly recommend this but it is a working solution for now.I have some trouble in my project. This issue blocks me from using Formik. Waiting for resolve.