How to Fix Memory Leak in React useEffect Hook
useEffect happen when side effects like subscriptions or timers are not cleaned up properly. Fix this by returning a cleanup function inside useEffect that cancels or unsubscribes resources when the component unmounts or dependencies change.Why This Happens
A memory leak in useEffect occurs when asynchronous tasks, subscriptions, or timers continue running even after the component using them is removed from the screen. This causes React to try updating a component that no longer exists, wasting memory and causing warnings.
import React, { useState, useEffect } from 'react'; function Timer() { const [count, setCount] = useState(0); useEffect(() => { const intervalId = setInterval(() => { setCount(c => c + 1); }, 1000); // Missing cleanup here }, []); return <div>Count: {count}</div>; }
The Fix
To fix the memory leak, add a cleanup function inside useEffect that clears the interval or unsubscribes from any ongoing tasks. This cleanup runs when the component unmounts or before the effect runs again, preventing updates on unmounted components.
import React, { useState, useEffect } from 'react'; function Timer() { const [count, setCount] = useState(0); useEffect(() => { const intervalId = setInterval(() => { setCount(c => c + 1); }, 1000); return () => { clearInterval(intervalId); // Cleanup to stop the timer }; }, []); return <div>Count: {count}</div>; }
Prevention
Always return a cleanup function from useEffect when you start subscriptions, timers, or async tasks. Use linting tools like eslint-plugin-react-hooks to warn about missing dependencies or cleanup. Avoid updating state after the component unmounts by canceling async operations or using flags.
Related Errors
Other common errors include "Can't perform a React state update on an unmounted component" and stale closures causing outdated state updates. These can be fixed by proper cleanup and using refs or flags to track mounted status.