formik: Set Field Value not working when called from didmount
Current Behavior
When I call setFieldTouched and setFieldValue in the componentDidMount method, the value is not applied in the values object but in the touched object it is.
Steps to Reproduce
Expected behavior
1 Create a form with formik, it can be with the Form component or the withFormik hoc.
2 Call setFieldValue in the componentDidMount and check the values prop for any change.
Suggested solution(s)
Seems like in some way the form is not ready to change values, since a workaround could be to use the setState callback or setTimer( () => this.props.setFieldValue(), 0 )
Additional context
This happens in 1.0.3 since in 1.0.2 seems to work fine
CodeSandbox Link:
- Formik Version: 1.3.0
- React Version: 16.5.1
- TypeScript Version: na
- Browser and Version: Chrome 69.0.3497.100
- OS: MacOs High Sierra 10.13.6
- Node Version: 10.8.9
- Package Manager and Version: yarn 1.9.4
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 19
- Comments: 25 (1 by maintainers)
☝️ Stale? I’ve just encountered this issue and it’s pretty annoying, any fix in sight? 😕
@ericbiewener I can’t seem to find that a solution… right now using formik in a more complex way with nested dynamic fields is not possible.
and @AndreKelling I wouldn’t recommend on downgrading to 1.0.2 because it is before the performance fixes.
For anyone encountering this bug, I’ve found a workaround, it’s not pretty but it works. If our problem is that formik won’t initiate any updates until it is mounted, I used
setTimeoutwith 1msec to make sure what I want happens insidecomponentDidMountand after formik IS mounted.More broadly, you can’t call any of the FormikBag functions that modify the formik state, e.g.
form.setSubmitting(). This is because thedidMountflag in the<Formik>component doesn’t get set totrueuntilcomponentDidMount, butcomponentDidMountis called for child components before the parent.I’m not sure what a good solution is here. Adding
didMountto the formik state would allow child components to get notified of when the parent form has mounted, but this feels messy. Perhaps the FormikBag could include anonMount()method that takes a function as its sole argument. That function in turn would get called in thecomponentDidMountmethod of<Formik>The same issue, it’s not possible to populate dynamically form with some values inside
componentDidMountmethod.How you would want to get this working in componentDidMount lifecycle method without using setTimeout is to create an async method which calls the setFieldValue.
We are ultimately taking the approach I suggested in my previous comment. We already had a
Formclass component that wrapped the mainFormikcomponent. We have now added the following methods/properties:We then pass down
onMount: this.registerOnMountCallbackas an additional property on the usualFormikBagin the form’s render method.Forgive me if I’m not quite understanding the use-case of setting the value in the
componentDidMountmethod, but the implementation of setting values in the mount phase seems a little bit like an anti-pattern.Typically, if I’m initializing the form, I leverage two props provided by Formik:
initialValuesandenableReinitialize. I move theinitialValuesstate up to the parent component so that I can pass it as props down to the form component.enableReinitializewill allow the form to reset theinitialValuesonce they change in the parent component (either through an asynchronous network request or simply by setting the state). If you’re not setting the form dynamically through an async request, I would strongly suggest simply just setting the initial values statically as opposed to using setState in the mount phase (this will avoid an unnecessary additional render).Now, while this solves the values issue, it doesn’t solve the touched issue. My only work-around for that is using
componentDidUpdateto detect when the value populates in the form, then you can use thesetFieldTouchedI forked the first sandbox posted and altered it for this specific example. https://codesandbox.io/s/formik-example-8se6d
I’m not implying this isn’t a bug–I’d have to look at the code a little bit deeper to understand what’s happening, but I’m just suggesting a different approach that might avoid some other pitfalls.
I hope I understood the use-case enough and that this answer is both relevant and helpful!
Had to run a
validateForm()inside a componentDidUpdate, but kept validating using the previous values. Wrapping it in asetTimoutdid the trick.Same problem, can’t set field value on componentDidMount. I need to sync some form fields with redux store, but I can’t use mapStateToProps because it will reinitialize whole form… @jaredpalmer is possible to do something with this issue? Thanks
Same problem here with setFieldValue since 1.3.0 and the suggested workaround works for me as well, but I totally agree that it’s hacky.
I looked for the cause for the problem and this PR seems to be it: #895
Is this really wanted behaviour to prevent changing the state before the whole form component would be mounted? Thanks.
In React Native this worked for me:
I am also experiencing it with the
connect()method. Only after I handle it withsetTimeout(someFunction, 0)it works normally. But I don’t like it since it seems “hacky”.