formik
formik copied to clipboard
[v2] isSubmitting resets to false too early.
🐛 Bug report
Current Behavior
In 2.0.1-rc12, when submitting the form, isSubmitting is set to true but is instantly reset to false, making it hard to disable input fields and buttons.
Expected behavior
I would expect isSubmitting to be true until it's set to false in the onSubmit function.
Reproducible example
Codesandbox example. (Sandbox was deleted at some point, sorry)
Your environment
| Software | Version(s) |
|---|---|
| Formik | 2.0.1-rc12 |
| React | 16.8.6 |
| Browser | Google Chrome Version 76.0.3809.87 (64-bit) |
| npm/Yarn | 1.17.3 |
| Operating System | macOS 10.14.5 |
I just ran into this issue as well.
Confirmed
I ran into the issue as well and noticed that it works as I would expect if my onSubmit function returns a promise. isSubmitting is set to false first when the promise resolves.
What is the expected here?
Toggling state on promise resolution makes sense but signature of submitHandler is (values: Values, formikBag: FormikBag) => void.
Perhaps it should also accept (values: Values, formikBag: FormikBag) => Promise<T> and do what it does now?
Ran into this problem when implementing modal forms too in #1741.
Thanks for the write up. Will investigate
This is exactly my problem. Did anyone came-up with a workaround?
I had a similar issue in v1.5.8 which I was able to resolve by setting enableReinitialize to its default value false.
any updates on this issue? I'm having the same problem and it's causing issues disabling the submit button for me - breaking functionality. Setting enableReinitialize to false as suggested by @mhienle did not help :(
UPDATE: It seems that if I use async/await this works correctly
<Formik
initialValues={{ email: '' }}
enableReinitialize={true}
validationSchema={Yup.object({
email: Yup.string()
.email('Invalid email addresss`')
.required('Required'),
})}
onSubmit={async(values, { setSubmitting }) => {
console.log('submit')
await callApi()
}}
>
<Form>
<Field type="email" name="email" />
<ErrorMessage name="email" component="div" />
<SubmitButton />
</Form>
</Formik>
note i don't use setSubmitting anywhere - it just seems to do it's thing all on it's own :S
@alexborisov did you try return await callApi()
As someone else suggested in my case my operation was async and I wasn't returning the promise. Seems like that would even be the intended behavior. If the onSubmit method doesn't return a promise it would assume it's done with the work.
@danecando yup returning async works for me. As does returning a promise. Thanks!
Do we need to update the docs around this?
Perhaps in the tutorial as well?
@jaredpalmer I believe it would be worth mentioning. I think in a previous version it worked fine with me handling the submit state manually in my async callback but it didn't work that way for me on v2. Not sure if this is new behavior or my memory sucks but returning the promise seems like a simpler api to me anyways.
Let me know I'll be happy to submit a pr sometime this week mentioning this behavior in the docs. PS: v2 is the :bomb: great work jared and contributors.
Here is an example of the issue. Just enter an email and click as many times as you can within 1 sec. See how submitCount increases.
https://codesandbox.io/s/formik-example-67mpu?fontsize=14
Also facing this issue
So returning async seems to work..
But how to handle dispatching redux actions on submit?
Returning the promise solved my issue in case anyone else faces this issue.
I am still getting the same problem, any solutions please?
Related to #1957 and #1987 sounds like
You should follow this approach https://github.com/relayjs/relay-examples/pull/118
you need both, ref and state to avoid double clicks/submits
Confirmed
Hi,
I just experienced this on "formik": "^2.0.4" as well. What is the fix for this?
What's the suggested solution here?
also this https://twitter.com/davidkpiano/status/1194616763000008705?s=21
we can return isSubmitting to user (to use as disabled on buttons), and use a ref to avoid double handleSubmit calls (this ref could be only for internal use)
@jaredpalmer #1987 is the solution many of us are hoping would be accepted which would allow many of us to not have to change the way we currently handle isSubmitting in v1.5.8. However, we're unsure if this is something you actually support. Otherwise, many of us have reverted to v1.5.8 for now. Thanks for taking a look at this!
@jaredpalmer So now that the isSubmitting state of Formik is controlled by the promise return in OnSubmit handler don't you think that exposing the setSubmitting method is stale.
@jaredpalmer So now that the isSubmitting state of Formik is controlled by the promise return in OnSubmit handler don't you think that exposing the
setSubmittingmethod is stale.
It's not. As the release note of v2.0.5 says:
HOWEVER, if your onSubmit function is synchronous (e.g. v1), then you need to still call setSubmitting(false) on your own
updating the documentation to mention that "Returning the promise" will give isSubmitting a better, not flakey value of the form's submittion state - would be awesome
So returning async seems to work..
But how to handle dispatching redux actions on submit?
@michielmetcake Have you tried something like:
const onSubmit={() => {
return new Promise((resolve, reject) => {
dispatchYourActions({type: '', value: [], resolve, reject, ...anyOtherData?})
// Make sure your action calls resolve or reject!
})
}}
I use redux-thunk and this works for me. Make sure your action returns a promise aswell!
const handleSubmit = (values, {setSubmitting}) => {
setSubmitting(true);
return dispatch(myAction(values))
.then(() => {
setSubmitting(false);
return Promise.resolve();
})
}
@jaredpalmer So now that the isSubmitting state of Formik is controlled by the promise return in OnSubmit handler don't you think that exposing the
setSubmittingmethod is stale.It's not. As the release note of v2.0.5 says:
HOWEVER, if your onSubmit function is synchronous (e.g. v1), then you need to still call setSubmitting(false) on your own
But still not works