Whenever if there is any asynchronous task performing related to component and that component unmounts then React generally gives this 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.
I found some solutions over internet to use isMount flag (either by using it with useRef or useState) as true and then updating it to false on component unmount. But is that a proper solution as per React site using isMount is a antipattern.
https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html
CodePudding user response:
In future version of React, you probably won't need to fix this. As React dev team is going to remove this warning in future release. The main reason being this warning can be false positive sometimes.
As per this commit by Dan Abramov https://github.com/facebook/react/pull/22114
But what are the solutions to fix this till that version release -
Using isMountState anti-pattern - If someone is checking isMounted in his code to fix this issue, then that person is already too late in performing this check, as this warning indicates the same check is done by React and it failed.
If this issue is because of an asynchronous call. Then one possible solution is to use AbortController API in your code. AbortController API helps in aborting any ajax call that is already made. Cool stuff. Right?
More details on this can be found here
So if it is a fetch API one can use AbortController API like this
useEffect(() => {
const abortController = new AbortController()
// creating an AbortController
fetch(url, {
signal: abortController.signal
})
// passing the signal to the query
.then(data => {
setState(data)
// if everything went well, set the state
})
.catch(error => {
if (error.name === 'AbortError') return
// if the query has been aborted, do nothing
throw error
})
return () => {
abortController.abort()
// stop the query by aborting on the AbortController on unmount
}
}, [])
If you are using axios, then good news is axios also provides support for AbortController APIs -
const fetchData = async (params) => {
setLoading(true);
try {
const result = await axios.request(params);
// more code here
} catch (curError) {
if (axios.isCancel(curError)) {
return false;
}
// error handling code
}
return null;
};
useEffect(() => {
const cancelToken = axios.CancelToken;
const source = cancelToken.source();
fetchData({
...axiosParams,
cancelToken: source.token
});
return () => {
source.cancel("axios request cancelled");
};
}, []);