Note: I've seen a lot of questions about this warning message, but most all of them seem to be about async fetching data right after mounting the component, whereas I'm trying to do a graphql mutation sent off on a form submission fired off by a click, so I don't think I can take a similar approach.
Also, I'm using hooks so a solution relevant to/using it would be nice.
I have a form in a reactstrap modal and on submit, do a graphql mutation. How do I make sure the component is not attempting to update state after being unmounted so as not to get this error?
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
The warning only occurs if a user navigates away from the page immediately after submitting. Most of the time a user would never do this, but instead would submit and then remain on the page for at least a couple seconds, in which case the warning never arises and there are no problems, but I don't want to take any chances.
Here is the handleSubmit code which is inside a form tag's onSubmit:
const handleSubmit = async e => {
e.preventDefault();
const contactToUpdate = {
id,
name: e.target.name.value,
email: e.target.email.value,
};
const addressToUpdate = {
city: e.target.city.value,
state: e.target.state.value,
street1: e.target.street1.value,
street2: e.target.street2.value,
zip: e.target.zip.value
};
const updateContact = updateCoordinators(
contactToUpdate,
addressToUpdate
);
try {
const apiData = await API.graphql(graphqlOperation(updateContact));
if (apiData) {
const newContactInfo = apiData.data.updatePerson;
setContactInfo(newContactInfo);
}
setToastType("success");
setShowSnackbar(true);
closeModal();
} catch (err) {
console.error(err);
setToastType("error");
setShowSnackbar(true);
}
};
The problem wasn't the mutation, but the snackbar! It was set to stick around for 3 seconds in a setTimeout which I didn't realize because I hadn't written that code. If the user clicked away before those 3 seconds were up, it would try to set its state for whether it showed itself to false even though it had now been unmounted, causing the warning. In the snackbar component, I put the setTimeout into a useEffect and cleared it in a callback on return so that if the snackbar component were unmounted, it would clear the timeout, thus never attempting to set state after unmounting, like this:
useEffect(() => {
const timeout = setTimeout(() => {
setShowSnackbar(false);
}, 3000);
return () => clearTimeout(timeout);
});