← Back to list

React useEffect Cleanup & Subscriptions

A cleanup function is used to remove resources when a component unmounts or before the effect runs again.

Gautam Makavana · 2026-06-13 05:29 · 0 claps · 2.8 min read
#nodejs #react #mern-stack
Open on Medium ↗
Wiki topics: 🌐 · Web Development

React useEffect Cleanup & Subscriptions

A cleanup function is used to remove resources when a component unmounts or before the effect runs again.

This helps prevent:

  • Memory leaks
  • Unnecessary API calls
  • Multiple event listeners
  • Multiple timers running simultaneously

Syntax

useEffect(() => {
  // Setup code
return () => {
    // Cleanup code
  };
}, []);

Flow

Component Mount
      ↓
useEffect Runs
      ↓
Setup Timer / Listener / Subscription
      ↓
Component Unmount
      ↓
Cleanup Function Runs

1. Cleanup Timer Example

Problem

Without cleanup, the timer continues running even after the component is removed.

import { useEffect } from "react";
function Timer() {
  useEffect(() => {
    const interval = setInterval(() => {
      console.log("Running...");
    }, 1000);
    return () => {
      clearInterval(interval);
      console.log("Timer Stopped");
    };
  }, []);
  return <h2>Timer Component</h2>;
}
export default Timer;

Output

Running...
Running...
Running...
(Component Unmount)
Timer Stopped

2. Event Listener Cleanup

Without Cleanup

Every render may add another listener.

Correct Way

import { useEffect } from "react";
function WindowResize() {
  useEffect(() => {
    const handleResize = () => {
      console.log(window.innerWidth);
    };
    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);
  return <h2>Resize Window</h2>;
}
export default WindowResize;

Why?

When component unmounts:

Listener Removed

No extra listeners remain in memory.

3. Subscription Cleanup

Imagine subscribing to a chat service.

import { useEffect } from "react";
function Chat() {
  useEffect(() => {
    console.log("Subscribed");
    return () => {
      console.log("Unsubscribed");
    };
  }, []);
  return <h2>Chat Room</h2>;
}

Output

Subscribed
(Component Unmount)
Unsubscribed

In real applications this could be:

  • WebSocket connections
  • Firebase listeners
  • Chat subscriptions
  • Notification services

Example: Toggle Component

App.jsx

import { useState } from "react";
import Timer from "./Timer";
function App() {
  const [show, setShow] = useState(true);
  return (
    <div>
      <button onClick={() => setShow(!show)}>
        Toggle Timer
      </button>
      {show && <Timer />}
    </div>
  );
}
export default App;

Timer.jsx

import { useEffect } from "react";
function Timer() {
  useEffect(() => {
    const interval = setInterval(() => {
      console.log("Tick...");
    }, 1000);
    return () => {
      clearInterval(interval);
      console.log("Cleanup Executed");
    };
  }, []);
  return <h2>Timer Running</h2>;
}
export default Timer;

Result

Tick...
Tick...
Tick...
Click Toggle
Cleanup Executed

The timer stops immediately.

Cleanup Before Re-running Effect

Cleanup also runs before the effect executes again when dependencies change.

import { useState, useEffect } from "react";
function Counter() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log("Effect:", count);
    return () => {
      console.log("Cleanup:", count);
    };
  }, [count]);
  return (
    <>
      <h2>{count}</h2>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </>
  );
}
export default Counter;

Output

Effect: 0
Click
Cleanup: 0
Effect: 1
Click
Cleanup: 1
Effect: 2

Common Memory Leak Mistakes

❌ Forgetting to clear intervals

setInterval(() => {
  console.log("Running");
}, 1000);

✅ Correct

const id = setInterval(() => {
  console.log("Running");
}, 1000);
return () => clearInterval(id);

❌ Forgetting event listener cleanup

window.addEventListener("resize", handleResize);

✅ Correct

window.addEventListener("resize", handleResize);
return () => {
  window.removeEventListener("resize", handleResize);
};

Interview Questions

What is a cleanup function?

A cleanup function is the function returned from useEffect. It runs when the component unmounts or before the effect runs again.

useEffect(() => {
  return () => {
    console.log("Cleanup");
  };
}, []);

Why do we need cleanup functions?

To prevent:

  • Memory leaks
  • Unused timers
  • Duplicate event listeners
  • Open subscriptions

When does cleanup run?

  1. When the component unmounts.
  2. Before the effect runs again due to dependency changes.

Quick Cheat Sheet

SideEffectCleanup

setInterval()

clearInterval()

setTimeout()

clearTimeout()

addEventListener()

removeEventListener()

WebSocketsocket.close()

Subscriptionunsubscribe()

Build a timer component with start/stop and cleanup.

import Timer from "./Timer";

function App() {
  return (
    <div>
      <h1>React Timer Demo</h1>
      <Timer />
    </div>
  );
}

export default App;

import { useState, useEffect } from "react";

function Timer() {
  const [seconds, setSeconds] = useState(0);
  const [isRunning, setIsRunning] = useState(false);

  useEffect(() => {
    let interval;

    if (isRunning) {
      interval = setInterval(() => {
        setSeconds((prevSeconds) => prevSeconds + 1);
      }, 1000);
    }

    // Cleanup Function
    return () => {
      clearInterval(interval);
      console.log("Interval Cleared");
    };
  }, [isRunning]);

  const startTimer = () => {
    setIsRunning(true);
  };

  const stopTimer = () => {
    setIsRunning(false);
  };

  const resetTimer = () => {
    setIsRunning(false);
    setSeconds(0);
  };

  return (
    <div>
      <h2>Time: {seconds} sec</h2>

      <button onClick={startTimer}>
        Start
      </button>

      <button onClick={stopTimer}>
        Stop
      </button>

      <button onClick={resetTimer}>
        Reset
      </button>
    </div>
  );
}

export default Timer;


메타데이터
post_id
baebfa42647d
slug
react-useeffect-cleanup-subscriptions-baebfa42647d
url
https://medium.com/@gm962460/react-useeffect-cleanup-subscriptions-baebfa42647d
canonical_url
https://medium.com/@gm962460/react-useeffect-cleanup-subscriptions-baebfa42647d
author_url
https://medium.com/@gm962460
status
ok
fetched_at
2026-06-20 20:29:01