Effects API π
Effects are like having a smart assistant that automatically does things when your data changes. Think of them as βreactive side effectsβ - they run automatically when signals change, perfect for logging, API calls, or DOM updates.
π― What are Effects?
Section titled βπ― What are Effects?βEffects run code automatically when signals change. Unlike computed signals that return values, effects are for side effects - talking to APIs, updating the DOM, or logging data.
@Component({ template: ` <div> <p>Count: {{ count() }}</p> <button (click)="increment()">+</button> </div> `})export class CounterComponent { count = signal(0);
constructor() { // β
Effect runs automatically when count changes effect(() => { console.log(`Count is now: ${this.count()}`); // Save to localStorage, send analytics, etc. }); }
increment() { this.count.update(c => c + 1); }}π Common Use Cases
Section titled βπ Common Use Casesβ1. Auto-Save Data
Section titled β1. Auto-Save Dataβ@Component({ template: `<input [value]="text()" (input)="updateText($event)" />`})export class AutoSaveComponent { text = signal('');
constructor() { effect(() => { // Auto-save whenever text changes localStorage.setItem('draft', this.text()); }); }
updateText(event: Event) { this.text.set((event.target as HTMLInputElement).value); }}2. DOM Event Listeners
Section titled β2. DOM Event Listenersβ@Component({ template: `<p>Window width: {{ windowWidth() }}px</p>`})export class WindowTrackerComponent { windowWidth = signal(window.innerWidth);
constructor() { effect((onCleanup) => { const handleResize = () => { this.windowWidth.set(window.innerWidth); };
window.addEventListener('resize', handleResize);
// β
Cleanup when component destroys onCleanup(() => { window.removeEventListener('resize', handleResize); }); }); }}3. API Calls & Data Sync
Section titled β3. API Calls & Data Syncβ@Component({ template: ` <div> <input [value]="searchTerm()" (input)="updateSearch($event)" /> <div>Results: {{ results().length }}</div> </div> `})export class SearchComponent { searchTerm = signal(''); results = signal<any[]>([]);
constructor() { effect(() => { const term = this.searchTerm(); if (term.length > 2) { // β
Automatically search when term changes this.searchAPI(term); } }); }
updateSearch(event: Event) { this.searchTerm.set((event.target as HTMLInputElement).value); }
async searchAPI(term: string) { const response = await fetch(`/api/search?q=${term}`); const data = await response.json(); this.results.set(data); }}β Best Practices
Section titled ββ Best Practicesβ1. Keep Effects Simple
Section titled β1. Keep Effects Simpleβ// β
Good - Simple, focused effecteffect(() => { localStorage.setItem('theme', this.theme());});
// β Avoid - Complex logic in effectseffect(() => { if (this.user() && this.settings() && this.preferences()) { // Too much logic here... }});2. Always Clean Up
Section titled β2. Always Clean Upβ// β
Good - Proper cleanupeffect((onCleanup) => { const interval = setInterval(() => { this.updateTime(); }, 1000);
onCleanup(() => clearInterval(interval));});3. Use for Side Effects Only
Section titled β3. Use for Side Effects Onlyβ// β
Good - Side effects (logging, API calls, DOM updates)effect(() => { console.log('User logged in:', this.user().name); this.trackUserActivity(this.user().id);});
// β Avoid - Use computed() for derived values insteadeffect(() => { this.fullName.set(this.firstName() + ' ' + this.lastName()); // Wrong!});
// β
Better - Use computed for derived valuesfullName = computed(() => this.firstName() + ' ' + this.lastName());π― Quick Checklist
Section titled βπ― Quick Checklistβ- Use effects for side effects (API calls, DOM updates, logging)
- Keep effect functions simple and focused
- Always clean up resources (event listeners, intervals, subscriptions)
- Use computed() for derived values, not effects
- Test effects by testing their side effects, not the effect itself
π Next Steps
Section titled βπ Next Stepsβ- Linked Signals - Advanced signal patterns
- Resource API - Async data handling with signals
- Control Flow - New template syntax with signals
Remember: Effects are perfect for bridging the gap between Angularβs reactive signals and the imperative world of DOM APIs, third-party libraries, and external services! π