Effect โ Side Effects with effect()
effect() runs a function whenever signals it reads change. Use it for side effects: logging, localStorage, API calls, DOM manipulation, syncing with non-Angular libraries.
effect() is a function that runs a callback whenever the signals it reads change. Think of it as a "watcher" โ when signal A changes, do action B.
"Effect = watcher โ signal badla toh kuch karo automatically."
import { signal, effect } from '@angular/core';
const count = signal(0);
// Register an effect
effect(() => {
console.log('Count changed to:', count());
localStorage.setItem('count', count().toString());
});
// When we change the signal, the effect runs automatically
count.set(5);
// Console: "Count changed to: 5"
// localStorage: "count" = "5"
Key characteristics of effect():
- Runs automatically when registered โ and again whenever read signals change
- Tracks signals automatically โ any signal you read inside effect() becomes a dependency
- Cleaned up automatically โ when the component is destroyed, effects are destroyed too
- Runs during change detection โ not immediately, but before Angular renders
โ ๏ธ IMPORTANT: effect() is for SIDE EFFECTS, NOT for deriving values. If you need a value to use in template, use computed(). Effect does NOT return a value.
Creating an effect is simple โ call effect() in the component's constructor or field initializer.
import { Component, signal, effect } from '@angular/core';
@Component({...})
export class SettingsComponent {
theme = signal('dark');
fontSize = signal(16);
// Effect in field initializer
private saveSettings = effect(() => {
localStorage.setItem('theme', this.theme());
localStorage.setItem('fontSize', this.fontSize().toString());
console.log('Settings saved:', this.theme(), this.fontSize());
});
changeTheme(newTheme: string) {
this.theme.set(newTheme);
// โ effect runs: saves to localStorage, logs
}
}
Angular automatically tracks which signals you read inside the effect. When theme() or fontSize() changes, the effect re-runs.
"effect automatically tracks which signals you read inside it โ jitne bhi signals padho, sab dependencies ban jayenge."
Effect runs in injection context: effect() must be called in an injection context (constructor, field initializer, or a function called from one). This is because it needs access to DestroyRef for auto-cleanup.
This is the most important distinction in signals: computed() is for values, effect() is for actions.
๐ computed vs effect โ The Golden Rule
| computed() | effect() | |
|---|---|---|
| Returns | โ A value (Signal) | โ Nothing (void) |
| Purpose | Derive state | Perform side effects |
| Pure? | โ Yes โ no side effects | โ No โ side effects expected |
| Used in template | โ Yes: {{ fullName() }} | โ No |
| Runs when | Dependency changes + someone reads it | Dependency changes |
| Performance | Cached, lazy | Runs eagerly |
// โ
CORRECT: computed for deriving values
total = computed(() => price() * quantity());
// Template: {{ total() }}
// โ
CORRECT: effect for side effects
effect(() => localStorage.setItem('total', this.total().toString()));
// โ WRONG: computed with side effect
bad = computed(() => {
localStorage.setItem('count', this.count().toString()); // Side effect!
return this.count() * 2;
});
// โ WRONG: effect for deriving value
effect(() => {
this.double = this.count() * 2; // Should use computed!
});
"computed = calculator (returns value), effect = alarm (does action)."
Rule: If you need a return value โ computed(). If you need to DO something โ effect(). Never use effect() to set another signal โ use computed() or .update() instead.
effects can have cleanup โ a function that runs BEFORE the effect re-runs and when the component is destroyed.
import { effect } from '@angular/core';
effect((onCleanup) => {
const timer = setInterval(() => {
console.log('Tick:', count());
}, 1000);
// Cleanup function โ runs before next effect run and on destroy
onCleanup(() => {
clearInterval(timer);
console.log('Timer cleaned up');
});
});
"Cleanup = mopping โ pehle purana saaf karo, phir naya lagao."
Why cleanup matters:
- Prevents memory leaks โ intervals, subscriptions, event listeners
- Prevents stale data โ old API response vs new response
- Prevents multiple instances โ count changes sets interval again without clearing old one
// Without cleanup โ BUG!
effect(() => {
setInterval(() => console.log(count()), 1000);
// Every time count changes, NEW interval starts!
// Old ones keep running โ memory leak!
});
// With cleanup โ CORRECT!
effect((onCleanup) => {
const id = setInterval(() => console.log(count()), 1000);
onCleanup(() => clearInterval(id));
// Old interval is cleared before new one starts
});Here are real-world use cases where effect() shines:
1. Auto-save to localStorage
effect(() => {
const settings = this.settings();
localStorage.setItem('app-settings', JSON.stringify(settings));
});
2. Sync with non-Angular library (Chart.js, Leaflet)
chartEffect = effect(() => {
const data = this.chartData();
this.chartInstance.data.datasets[0].data = data;
this.chartInstance.update(); // Re-render chart
});
3. Console logging for debugging
logEffect = effect(() => {
console.log('๐ User:', this.user(), '| Theme:', this.theme());
});
4. Show toast notification
notificationEffect = effect(() => {
const err = this.errorMessage();
if (err) {
this.toastService.show(err, { duration: 3000 });
}
});
5. Document title update
titleEffect = effect(() => {
document.title = `${this.pageTitle()} โ BiryaniHub`;
});
"effect = bridge between Angular signals and outside world โ localStorage, DOM, libraries, APIs โ sab kuch."
โ ๏ธ Don't overuse effect! If a template can handle it (show/hide, class toggle), don't use effect. Effects are for IMPERATIVE actions that the template can't handle declaratively.
Key Takeaways
- โ effect() runs a callback when signals it reads change โ for side effects
- โ NOT for deriving values โ use computed() for that
- โ Auto-tracks dependencies โ signals read inside effect() are tracked
- โ onCleanup() โ runs before effect re-runs and on component destroy
- โ Use cases: localStorage, logging, DOM updates, library sync
- โ DON'T write to signals inside effect that are part of the same dependency chain
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login