Angular Academy · Lesson

Effect Cleanup and Lifecycle

Clean up resources inside effects.

Lesson 3 of 413 steps

Effect Cleanup and Lifecycle is a free Angular Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Angular Academy learning path, and your progress syncs across the web and the CoddyKit app. The Angular Academy course includes 4 lessons in total.

Why cleanup matters

An effect can start resources: timers, subscriptions, event listeners. Each time the effect re-runs, the old resource must be torn down first — otherwise you leak timers and listeners. Angular provides an onCleanup hook for this.

The onCleanup callback

The effect function receives an onCleanup function. Register a teardown callback with it; Angular calls it before the next run and on destroy.

import { effect } from '@angular/core';

effect((onCleanup) => {
  const id = setInterval(() => console.log('tick'), 1000);
  onCleanup(() => clearInterval(id));
});

Cleanup runs before each re-run

When a dependency changes, Angular first calls the registered cleanup, then runs the effect body again. This guarantees only one active resource at a time.

const delay = signal(1000);

effect((onCleanup) => {
  const id = setInterval(() => console.log('tick'), delay());
  onCleanup(() => clearInterval(id)); // clears old interval first
});

delay.set(500); // old interval cleared, new one started

Cleanup of event listeners

DOM listeners added in an effect must be removed in cleanup to avoid duplicate handlers and leaks.

effect((onCleanup) => {
  const handler = () => console.log(window.innerWidth);
  window.addEventListener('resize', handler);
  onCleanup(() => window.removeEventListener('resize', handler));
});

Cleanup with subscriptions

If an effect subscribes to an Observable, unsubscribe in cleanup. (Often you would use other tools, but this shows the pattern.)

effect((onCleanup) => {
  const sub = interval$.subscribe(v => console.log(v));
  onCleanup(() => sub.unsubscribe());
});

Cleanup on destroy

When the component owning the effect is destroyed, Angular runs the final cleanup automatically, then destroys the effect. No leaked timers remain.

Order: cleanup then body

The very first time an effect runs there is nothing to clean up. From the second run onward, the sequence is always: cleanup -> body.

let runs = 0;
effect((onCleanup) => {
  runs++;
  console.log('run', runs, dep());
  onCleanup(() => console.log('cleanup before run', runs + 1));
});

Avoid heavy work without cleanup

Any long-lived resource started in an effect should have matching cleanup. A common bug is forgetting cleanup, causing intervals to stack up on each dependency change.

manualCleanup option

For effects created outside a component (e.g. in a root service that lives forever), you can use the manualCleanup option, then call ref.destroy() yourself when appropriate.

const ref = effect(() => {
  console.log(value());
}, { manualCleanup: true });

// You are now responsible for:
// ref.destroy();

DestroyRef as an alternative

For non-effect teardown you can inject DestroyRef and register callbacks with onDestroy. Inside effects, prefer onCleanup for per-run teardown.

import { inject, DestroyRef } from '@angular/core';

const destroyRef = inject(DestroyRef);
destroyRef.onDestroy(() => console.log('component destroyed'));

Putting it together

A debounced sync effect: each value change cancels the previous timer and schedules a new save.

const query = signal('');

effect((onCleanup) => {
  const q = query();
  const id = setTimeout(() => save(q), 300);
  onCleanup(() => clearTimeout(id));
});

Quick Check

Test your understanding of effect cleanup.

Recap: Effect Cleanup & Lifecycle

Use the onCleanup parameter to tear down resources started inside an effect.

  • Cleanup runs before each re-run and on destroy.
  • Always clean up timers, listeners, and subscriptions.
  • manualCleanup for long-lived effects; DestroyRef for general teardown.

Next: linkedSignal and advanced patterns.

Free to start

Learn HTML with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
38
Lessons
144

Frequently Asked Questions

Is the “Effect Cleanup and Lifecycle” lesson free?

Yes — any 3 lessons of the Angular Academy learning path, including “Effect Cleanup and Lifecycle”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Angular Academy course includes 4 lessons in total.

What will I learn in “Effect Cleanup and Lifecycle”?

Clean up resources inside effects. You practise Angular Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Angular Academy?

No prior experience is required. Angular Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “Effect Cleanup and Lifecycle” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Angular Academy lesson?

Yes. Every Angular Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Computed Signals
  2. Effects and Side Effects
  3. Effect Cleanup and Lifecycle
  4. linkedSignal and Advanced Patterns
← Back to Angular Academy