Effect Cleanup and Lifecycle
Clean up resources inside effects.
Effect Cleanup and Lifecycle is a free Angular Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Angular Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
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 startedCleanup 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.
manualCleanupfor long-lived effects;DestroyReffor general teardown.
Next: linkedSignal and advanced patterns.
Frequently asked questions
Is the “Effect Cleanup and Lifecycle” lesson free?
Yes — the full text of “Effect Cleanup and Lifecycle” is free to read here on the web, and the Angular Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Angular Academy course, upgrade to CoddyKit PRO.
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; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
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
- Computed Signals
- Effects and Side Effects
- Effect Cleanup and Lifecycle
- linkedSignal and Advanced Patterns