Let’s start with what memory leakage is and how this happens.
A memory leak occurs when the application holds the memory for variables or functions that are no longer needed. This causes degradation of the application in terms of performance over time. In React applications, memory leakage happens due to not handling asynchronous calls well, event listens not being updated, and event times not being updated or not handled when component updates. In reaction, we have a virtual state that needs to be updated, and memory needs to be cleared as soon as we are done with our work.
What causes memory leaks in React?
1. Not clearing Event Listeners: When we have an Event listener, and if we miss, remove it when the component unmounts or updates.
useEffect(() => {
const clickEvent = () => console.log("Click Event");
window.addEventListener("click", clickEvent);
return () => {
// Event needs to be removed to avoid memory leaks
window.removeEventListener("click", clickEvent);
};
}, []);
So, don’t forget to add removeEventListener when you have an event.
2. Uncleared Timers: When we have setTimeout or setInterval, add clearTimeout or clearInterval, respectively.
useEffect(() => {
const timer = setInterval(() => console.log("timer"), 2000);
return () => {
// Add clearInterval to avoid memory leak
clearInterval(timer);
};
}, []);
// Another snippet for setTimeout with componentDidMount() is as below:
componentDidMount() {
this.timeoutId = setTimeout(() => {
console.log("Timeout finished!");
}, 5000);
}
componentWillUnmount() {
// Add clearTimeout to avoid memory leak
clearTimeout(this.timeoutId);
}
3. Unsubscribed observables
useEffect(() => {
const subscription = myObservable.subscribe((data) => console.log(data));
return () => {
// Unsubscribe the observable's subscription to avoid memory leaks
subscription.unsubscribe();
};
}, []);
4. Not updating the state during asynchronous calls: When we have to work on asynchronous calls, for example, handling API calls, update the state of the component when it is unmounted.
useEffect(() => {
let isMounted = true;
fetch("/api/data")
.then((data) => {
if (isMounted) {
setState(data); // Set the value to false once done with the state
}
});
return () => {
// Update the component's state when this line is encountered
isMounted = false;
};
}, []);
5. When trying to update the state of the component once unmounted, it also causes a memory leak.
Let’s see how we can identify Memory leaks in any react application.
Browser’s Development Tools
- We have a memory tab in Chrome’s dev tool where we can record the heap snapshots and other objects.
- We have a Performance monitor to track real-time memory usage.
Here is a screenshot of Amazon for heap snapshot.
React profiler
We can use a profiler in React development tools to analyze how components are rendering and identify unnecessary updates.
Also, we have React developer tools, which are Chrome extensions, as we can see in the screenshot below. We will see the ‘Components’ and ‘Profiler’ tabs in our Chrome development tool.
Use third-party tools
Using Lighthouse and monitoring tools like Datadog and Sentry can help to understand the performance issues caused by memory leakage.
Here is how we can get an audit report with Lighthouse: Click on the Analyze page load and wait for some time till it generates the report.
Now, let’s see what happens if we have memory leaks.
- Slow performance: Performance of the application would be slow after over usage of memory. Meanwhile, the efficiency of the application goes down.
- UI becomes unresponsive: Due to overuse of the memory components, it will be less effective in performance.
- Warnings: We would see warnings on the console about unmounted components and state updates.
So don’t forget to clean the space whenever you are coding!
And that’s all. Happy Day!
Please visit my profile for more information on web development.