-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[v2] Validation runs on old values after setFieldTouched #2083
Comments
Not sure if the #2116 should have closed this issue or not, but i believe this is still a problem in
Upgrading |
Both setXXX will are called synchronously in your example. setFieldTouched thus doesn’t wait for setFieldValue. Because hooks are annoying af, there is no way for us to provide a promise or callback after the commit AFAIK. Thus my suggestion is then to call setFieldValue first and let it run validation as side effect and then call setFieldTouched but abort validation. |
My point above is that this isn’t a bug, it’s how React works. |
Thank you for the explanation! |
I understand that, but isn't there way, how to avoid this behavior if Or what is, in this case, the best way how to create custom Formik-hooked components that need to set the value (of course) as well as set they're touched - e.g. I don't want to Thanks for any insights |
I'm running into something similar, but it's with validation? Can someone help since this was working fine in Formik 1.x, but is now validation in Formik 2.x never seems to work correctly when using I tried the recommendation of using setFieldValue, then setFieldTouched and then validateField, but the field I am using is still not valid for some reason. My code looks like so (a custom Field.)
In this case, 'Size is required' is showing up, even though I am setting a new value. The only time it starts to validate correctly is when I click away from the and then it finally validates. But why is it not validating when I select an option? |
If I print out the formik values, they look like so (after selecting an option.). It goes from invalid, valid to invalid again.
then another render which makes it suddenly valid?:
Then another render which suddenly makes it invalid?
|
I am unsure how to fix this, but my issue was if I enabled I think I may open another bug report since I think it is unrelated to this. Looks like this is what I am running into: |
My solution looks like this for form-level validation
|
So anywhere I'm using Formik 2.x and I use setFieldValue() or setValue() with the form I use the following component to wrap the Formik component's children to correctly validate the form. Is this the best workaround?
|
If you have that option you can call setFieldTouched from onBlur handler. |
you can use the following, it worked for me setTimeout(() => setFieldTouched(value, true)) Wrap |
The setTimeout method fixed this issue for me with my React-Select fields. |
This is not a good idea. It works but, the component is looping. My solution for not looping it's put this block code inside component:
|
@wallace-sf can you please provide a better code snippet of how you are using your code? I was going to create another component just to trigger validations but I see that you are using the specific value of the field that needs validation. Thanks! |
Sure. Take a look of using a rating component (lib react-rating)
|
@wallace-sf thank you so much for the example. I have been pulling my hair out for almost a week now with validations doing strange things in various places after upgrade to 2.x. Note that this only worked for me in 2.2.5 (2.2.1 did not work). To the comments above If we can work around the problem by adding hooks to our components there has be a way for formik to handle in a reliable way. |
@gone-skiing agreed. "it's how react works" is not the final answer, but because the current Formik implementation relies on React hooks to manage state internally, a render is required to update the values passed to the callbacks, resulting in stale validations. Formik state should be separated from React hooks in a future major version, see my comment here: #2846 (comment) |
@johnrom thanks for the comment. It is great to see that the team is thinking about it. |
@johnrom @jaredpalmer |
@leo-terratrue That would get you halfway there, but then you'd still have an issue with async validation - in the example where you call set state one after another: setState(newValues) // runs validation 1
setState(evenNewerValues) // runs validation 2
// validation 2 completes
// validation 1 completes - user sees 'stale' errors from validation 1 It's not really a hooks vs other implementation approach, but the fact that Formik needs to use a reducer (or even better, state machine) pattern, so that updates can be queued and processed in sequence. Then, in the case of validation (which runs asynchronously), 'stale' validation results need to be ignored, rather updating state. All that's achievable with hooks I think 🙏 |
@andycarrell That isn't really the case that I'm describing; I was mainly responding directly to @jaredpalmer's comment about being unable to add a promise or callback that runs after the state commit with hooks. What I'm referring to would enable, in general, running some side effect after an update to formik state completes. like so:
You could trigger your async validation by calling it on updatedFormikState from within that returned promise's resolved handler (or an equivalent callback param). To do multiple sequential updates and validations, you'd just chain further updates in additional promises. It is a hooks vs. other implementation issue- that API is not possible with useState. |
Stop sending me messages from this email.
All efforts to unsubscribe is futile.
Stop sending me messages from this email.
Thank you 🙏
…Sent from my iPhone
On 18 Nov 2020, at 05:32, leo-terratrue <[email protected]> wrote:
@johnrom<https://github.com/johnrom> @jaredpalmer<https://github.com/jaredpalmer> Because hooks are annoying af, there is no way for us to provide a promise or callback after the commit AFAIK. Agreed that this is annoying- making it possible have a callback or promise that runs after setFieldValue's state update is complete would be very useful. But the easy solution to that feels like simply not using hooks for that state in the Formik implementation. Regular class component setState offers the second (callback) parameter, which would enable exactly this. Is there a reason that isn't an option? Adding a callback/promise to APIs like setFieldValue which receives the new formik state as a parameter (implemented internally using class component setState) fees like the easy 80/20 solution to a lot of these kinds of issues. The lack of something like that has been a pretty major pain point for us in using Formik.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#2083 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AQORP75NTGQFVT7KNOFRO4LSQNE4JANCNFSM4JTUZFKQ>.
|
I've built a number of large forms in an app using hooks from useFormikContext and only just discovered this validation issue. The solution I've come up with is to add this component to forms that use these hooks:
It just listens to values and revalidates whenever they change, which has solved this for me. |
@tj-mc thank you for the code example. Looks like some form of this approach is what helps address this issue. I guess what I am wondering if the problem can be solved with 8 lines of code, should not this be integrated into the formik code base? |
@gone-skiing No worries. I don't really have a good understanding of the inner workings of Formik, so I'm not sure why this is unsolved as of right now. All I do know is that this issue took ages to find a discussion on and caused me a lot of confusion. Hoping it can be resolved soon, but in the meantime I don't think I'll be using Formik hooks. |
Same here - probably about a week of wasted effort for me, it is such a rake. Failure cause is very difficult to track and I can't advocate strongly enough to fix it as soon as possible. |
@gone-skiing @tj-mc the solution presented will not make it into the Formik API itself for a variety of reasons. Using an effect, validation does not begin until the render is committed, which could result in validation lag for every project using Formik. Adding it in addition to the current callback-based method results in duplicate validation which would be a performance regression in projects which aren't experiencing this issue. The solution that works for everyone requires a rewrite of the way Formik accesses state internally, which is a complex issue that we'll be targeting for v3. |
Thought I'd add that my previous hack-fix has not really proved reliable, so don't reach for this as a production-ready solution. Plus as @johnrom pointed out, it's just gonna cause lots of re-validation and re-renders. In my app I managed to get away with not using Btw, Thanks for all your work on this library guys, in all my time using it, this would be the only time it's got in my way. |
+1 |
Any progress on this? I am still having this issue and haven't been able to upgrade from 2.1.4 because of it |
You can follow the state updates here: #3089 |
Encountered the same issue on If you are using both setFieldTouched(fieldPath, true, false) // do not validate
setFieldValue(fieldPath, newValue, true) // do validate |
Disabling |
Once this issues gets resolved, please do notify... |
looks like there might be a workaround in using setValues((fields) => ({...fields, someField: newValue}, true)) guessing because that's no longer running sync? |
Thank you @vicasas - that solution worked for me. I'm running React 18.2 and Formik 2.2.9
|
this solution will work also :
|
FYI, the On Chrome, the workaround works flawlessly by letting the values get up to date before running validation. @oussidr The Promise syntax with the latest version of |
After investigating formik source code I found intresting line of code formik/packages/formik/src/Formik.tsx Line 185 in 0f960aa
ref value is set to new variable and then used everywhere, because of that when stateRef.current is updated here state variable still has old reference(until next render) which is used for validation in setFieldTouched method here
Replacing state.values with stateRef.current.values garantees that validation will always run on actual values. I submitted PR with this change. |
@Jestermaxrko I've been using your fork, it seems to work well. Now I can remove all these |
Any predictions if this fix will be released in versions 2.x or just 3.x? |
🐛 Bug report
Current Behavior
Calling
setFieldTouched
runs validation on old values.Expected behavior
Validation should be called on new values.
Reproducible example
https://codesandbox.io/s/formik-codesandbox-template-yqrgc
I can get around this issue with replacing
with
Additional context
Related problems I could find: #1977, #2025
Your environment
The text was updated successfully, but these errors were encountered: