formik: Calling setFieldValue in response to a field change is out of sync with validations
🐛 Bug report
Current Behavior
The example im working with is let’s say i have two drop down menus 1 & 2.
When menu1 changes, i want to reset the value of menu2. When I do this, and both fields are required, both menu1 & menu2 are invalid, even though menu1 has a value.
Expected behavior
I am updating the value of menu2 in componentDidUpdate when formik.values.menu1 changes. I feel like calling setFieldValue('menu2,' '')
should be safe.
Reproducible example
https://gist.github.com/agmcleod/921c5798c4ba7285bc12bff8ebd6d82b
I tried to use the code sandbox templates, but yup validations werent working there for some reason.
Suggested solution(s)
Your environment
Software | Version(s) |
---|---|
Formik | 2.0.6 |
React | 16.12.0 |
Browser | Firefox |
npm/Yarn | yarn 1.13.0 |
Operating System | MacOS Mojave |
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 30
- Comments: 36
I had a similar issue and solved it by calling
setFieldTouched
in a timeout.Solution without
setTimeout
is here:Pay attention that function setFieldValue in formik is an async function(it returns a Promise), therefore, when you want to change x field value as a result of y field , you have to put the calling for setFIeldValue on y field in a callback to the first setFieldValue call: for example:
onChange= (_, value) => { setFIeldValue(x, value).than( (res) =>{ setFieldValue(y, /* your desired value */) } }
(or using async await syntax sugaring)
I was just bitten by this issue and
await
onsetValue
helped me. I was actually considering it before, but bc the docs says it’s return value is “void
” I didn’t even bother trying it out.I’m confused on what grounds has this issue been closed. There is no resolution or recommendation attached to closing it. I would expect to at least fix the bug in the docs or ideally provide a recommendation or even a link to the docs where this is explained.
(On a higher level, an API where one has to
await
forsetValue
before being able to callsetTouched
, and if not then there is no exception reported, but thesetValue
silently does not work, looks brittle at least, if not wrong.)The gist is not loading for me on my network but I was having a similar issue and figured I’d mention it in case it helps someone else while upgrading…
I had multiple selects using setFieldValue but the validation always seemed to be one step behind. In my change handler I was calling setFieldValue and then setFieldTouched to touch and set the value of the field. Both of these functions trigger the validate function and it looks like the setFieldTouched function was returning last and running using the value of the field before it was updated. This showed the field as invalid even though it had a value.
In short I just updated the setFieldTouched function to not validate the form.
// Set field to touched but do not trigger validation
props.form.setFieldTouched(field.name, true, false);
Anyways, for others coming across this, I was able to get it to work with the following:
Where
DEFAULT_VALUE
is some default value I want my fields to clear to when hidden, andDEFAULT_TOUCHED
is false.The
await
is key here, which the type definition does not include (see PR linked in comment above)^ it seems the typescript definition for setFieldValue is wrong; it shows return value as void but this fix worked great for me when nothing else did.
I had the same “trouble” and saw this issue here at GitHub today, there is still no update in the docs and types.d.ts-file of the packages, at least what I can see?!
still:
setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void;
instead of:setFieldValue: (field: string, value: any, shouldValidate?: boolean) => Promise<void>;
I had to overwrite the types in my project manually and then it works fine with async-await - but
setFieldTouched
works as expected asvoid
without `Promise<void>, the potential of causing some issues is high if you come back to your code later, so always need to provide comments with the link to this issue:Are there any plans to update this - or do I miss something? 😃
I’m still getting this issue at version
2.2.9
Fixed by @sapkra 's approach However, it makes code long and not descriptive. I hope there will be a patch for it soon 😃worked me
Is there any other solution because it is ultimately a problem or not?
I am having this same issue on Formik latest version is
2.4.5
😿 This should definetely be reopened.@brandonlenz 's workaround did work for me, but the impression I get is that touched doesn’t really have anything to do with the problem, the fix works simply because it retriggers the validation which should be handled by setValue in the first place. It is the same workaround as calling setValue again on a setTimeout.
@jaredpalmer would you mind re-opening this issue please?
does Formik receive any updates on this topic and in general in a whole codebase? I overcame this problem by doing my own
setFieldValueAndValidate
function. It would be really awesome if this will be marked as an open issue ✌️this guy has awesome solution https://stackoverflow.com/a/57684307/4445575
I am having the same issue using
"formik": "^2.4.5"
addingsetFieldTouched
does not work on Safari, it works only in ChromeI am also facing the same issue with “formik”: “^2.1.4”. any solution for this apart from using a timeout, which seems really hacky.
Shouldn’t the setFieldTouched() be called inside the setFieldValue() as part of default implementation of setFieldValue ?
Just fyi, I’m still getting this on
v2.2.9
. I solved it using thesetTimeout
on everysetFieldTouched
call. I wasn’t able to test using await, as I’m using typescript and the type signature shows it just returningvoid
, not aPromise
. 😃I run into this.
My solution, call
setFieldTouched(name)
beforesetFieldValue(name, value, true)
. Then the validation will work as normal 😃setTimeout solved the issue. thanks!
There are PRs which are changing this type + docs but they are still not merged: https://github.com/formium/formik/pull/2648 https://github.com/formium/formik/pull/2384