Open RyanAtViceSoftware opened 4 years ago
It looks like the warning is occurring because by the time you call signIn, isAuthenticated is going to start returning true, so you're going to start rendering <Redirect />
instead of your <BusyIndicator />
; thus, since Formik is no longer rendering, it was already unmounted, and can no longer be updated. Basically, you don't need to do anything in the then()
because by the time it is called, Formik is gone and there's nothing to reset. You can either remove the then()
callback, or hide formik via css instead of removing it from the render.
@johnrom I maybe approaching this wrong but how would I handle and error coming back from the server then? Seems like my current design needs to be rethought.
I'm not sure the signature of your sign In method, but if it returns a condition that results in Formik continuing to render, you can continue to use your callback with that check.
signIn().then(result => {
if (!result.isAuthenticated) {
setSubmitting(false);
// etc
}
});
The warning maybe possible to work around in this particular example, but within a more complex application setup, I think it's reasonable to do:
@withFormik({
handleSubmit: async (values, {props, setSubmitting}) => {
try {
await props.callSomeServerAction(values);
} finally {
setSubmitting(false);
}
},
})
class TheComponent extends React.Component {...}
Maybe this issue is specific to class components and doesn't happen with functional components. Maybe it's wrong to do setSubmitting(false)
in a finally
block?
If one of the impacts of callSomeServerAction()
is to unmount the component (from the "outside"), then it's quite difficult to learn about this here and to skip the setSubmitting(false)
call.
Or continuing the example above, imagine that result.isAuthenticated
is a really complex condition that (1) is already evaluated elsewhere higher in the stack and (2) involves other values present (only) there. It would be nice/convenient if the form didn't have to re-evaluate this and could safely call setSubmitting()
.
I wonder if it would be easier for Formik to check whether it is still mounted within setSubmitting. There should technically be no issue here. The warning is mostly for situations where code continues depending on unmounted components.
Once this callback is completed, references to the component should be garbage collected properly and thus there shouldn't be a memory leak - but I don't have a repro in front of me to confirm that. If that's the case, there's no problem calling setSubmitting after the component unmounts and we should make the check within Formik if possible.
@johnrom I think that's a good suggestion.
Here's the repo that has the issue: https://github.com/vicesoftware/react-redux-hooks-boilerplate
It's a boilerplate so it's not over complex and weighted down with business logic. It's well documented and quick and easy to run. It's the signin component that has the issue.
It's not ideal, but you can check if the future state of redux is isAuthenticated
like this:
const MyForm = () => {
const store = useStore();
return <Formik
onSubmit={() => signIn.then(() => {
if (!store.getState().authentication.isAuthenticated) {
resetForm();
setSubmitting(false);
}
})}
/>;
}
I'm still on the fence about whether to make this check in Formik.
My solution is just to check if location.pathname
has not changed.
if (location.pathname === '/sign-up') setSubmitting(false)
Is that the proper solution or just a workaround around a formik bug? I.e. should this actually be closed?
Needs further evaluation
I encountered this issue when a field error was returned from my server because of how I was rendering my loading spinner. My errors were trying to return from the server and my Formik component was unmounted. i.e. I do not believe this is a Formik specific issue.
My code..
const SignIn = () => {
const [{fetching}, signIn] = useSignInMutation();
// THIS WAS CAUSING MY ERROR
if(fetching) {
return <LoadingSpinner />
}
....
return (
// RESOLVED BY CALLING MY LOADING SPINNER HERE
{isSubmitting && <LoadingSpinner />}
)
}
Note* I was not having this issue with a successful login.
I solved my issue with the following solution, it worked for me. Place the 'isAuthenticated' just outside of your
I encountered this bug in a different scenario where I couldn't simply check a store state.
FWIW, I think it's reasonable for Formik to handle this, since the usage of setState
within actions.setSubmitting
is an implementation detail. Having to manage Formik's internal state code outside of Formik is non-intuitive.
That said, I was able to fix this in my code using this method of using hooks to see if my wrapper component was mounted before calling setSubmitting
.
Ideally this check would be made within Formik
; it was a minor fix for me, since I have a wrapper Form
component that all my forms use. But anyone who is using Formik
without a wrapper component will have to have separate code in each form to perform this check.
🐛 Bug report
Current Behavior
I'm getting this error
For this component
Expected behavior
To not get a warning
Reproducible example
https://github.com/vicesoftware/react-redux-hooks-boilerplate/tree/formik-warning-demo
cd webapp
npm install
npm start
http://localhost:3000/signin
ryan@vicesoftware.com
andpassword
see warning
Suggested solution(s)
Additional context
Your environment