I have a component that has 3 charts(graphs), using React.js as a framework, Highcharts
and HighchartsReact
to create the charts.
To populate data to these charts, I make 3 requests to the server, to provide data for each chart.
When the component mounts, it makes the requests(using Axios), awaits for the response, passes the data to the chart, and then displays/draws in the DOM.
The way the app is structured:
Axios files:
- utils(get, post, put calls)
- interceptors
Components:
- App.jsx
- Root.jsx
- Charts.jsx
- Other pages.jsx
- Root.jsx
Root.jsx:
its in this component that the chart component and other pages will display).
It has a navbar that, for example, when you click in the charts icon in the navbar, it will redirect to the chart page.
The navbar is always there.
Using react-router-dom to deal with the re-directions.
The problem:
While the requests are being made, if I access another page(same app), and the component unmounts, I get the 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.
How do I deal with this?
Should I:
- Stop the requests on url change?
- Stop requests when the component unmounts?
- Other solutions??
I tried abortController but couldn’t make it work.
Honestly, I don’t even know if it makes sense to use it in my case.
// axios utils
export const apiGetCall = (url) => axiosInstance.get(url);
// One of the function to get data from server and pass to chart
useEffect(() => {
const fetchData = async () => {
try {
const response = await apiGetCall("/departments");
const departmentsData = response.data.departments;
// Update the state with the fetched department data
setDepartmentData(departmentsData);
// Move the contents of pieChartOptions to the useState hook
setPieChartOptions({
// Department data
});
} catch (err) {
console.log(err);
}
};
fetchDepartmentData();
}, []);
I just inserted the relevant code. The chart display etc. is working fine.
I just need help dealing with the error.
2
Answers
Another option is to upgrade to version 18 of react, which removed this warning. It was removed, in part, because it can be misleading: your code doesn’t actually mave a memory leak. You fetch data once, set state, then return. At that point, javascript can clean up closure variables. A persistent subscription could result in a memory leak (eg, a websocket that you forget to teardown), but you aren’t doing that.
If you’d like to get rid of the warning without changing react versions, then you should add a cleanup function to your effect. You’ll save a variable indicating it has unmounted, and then skip setting state if that variable has been set.
This warning is indicating that some asynchronous code/callback is still running even after the component that initiated the call has since unmounted. When a component unmounts you should cleanup these "connections" so there are no resource leaks.
In the past an "isMounted" check was established as a way to check if the component was still mounted and conditionally not attempt state updates, but this has since fallen out of recommendation and is considered a React anti-pattern.
Here you should use an abort token to cancel any inflight network requests when the component unmounts. (Pattern is very similar to the older "isMounted" logic).
See the AbortController and Axios Cancellation docs for details.
Example implementation: