0
0
ReactDebug / FixBeginner · 4 min read

How to Fix Memory Leak in React useEffect Hook

Memory leaks in 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.

jsx
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>;
}
Output
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak.
🔧

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.

jsx
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>;
}
Output
Count increments every second without warnings or memory leaks.
🛡️

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.

Key Takeaways

Always clean up side effects in useEffect by returning a cleanup function.
Clear timers, cancel subscriptions, and abort async tasks to prevent memory leaks.
Use linting tools to catch missing dependencies and cleanup in useEffect.
Avoid updating state after unmount by tracking component mounted status if needed.
Proper cleanup ensures smooth performance and no React warnings about memory leaks.