It is common to issue an asynchronous request to an API in a useEffect hook. Perhaps to fetch some data which is eventually used to update component state. Something like this:
const [data, setData] = useState([]);
useEffect(() => {
axios.get('get/some/data').then(({ data }) => {
setData(data);
});
}, []);
It is also common to encounter a situation where the component unmounts before the request is complete. The callback will still be executed if the component unmounts because the request was not cancelled. Consequently, when setData
is called, this interesting warning pops up in the browser console:
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.
How to fix this
To fix this, the request needs to be cancelled when the component unmounts (in the useEffect
cleanup function). This can be easily achieved with axios
as follows:
const [data, setData] = useState([]);
useEffect(() => {
const cancelToken = axios.CancelToken.source();
axios
.get('get/some/data', { cancelToken: cancelToken.token })
.then(({ data }) => {
setData(data);
})
.catch((err) => {
if (axios.isCancel(err)) {
// TODO
}
});
return () => {
cancelToken.cancel();
};
}, []);
This can also be accomplished with fetch
using AbortController
as follows:
const [data, setData] = useState([]);
useEffect(() => {
const controller = new AbortController();
fetch('get/some/data', { signal: controller.signal })
.then((res) => res.json())
.then((data) => {
setData(data);
})
.catch((err) => {
if (err.name === 'AbortError') {
// TODO
}
});
return () => {
controller.abort();
};
}, []);
Top comments (2)
That was a nice read! Liked, bookmarked and followed, keep the good work!
Thanks 🙏