Angular Signals (stable since Angular 17) fundamentally change how Angular tracks and responds to state changes. Instead of running change detection across the whole component tree, signals allow Angular to know exactly which components depend on which state.
import { signal, computed, effect } from '@angular/core';
// Writable signal
const count = signal(0);
// Read a signal — call it like a function
console.log(count()); // 0
// Update signals
count.set(5);
count.update(c => c + 1);
const firstName = signal('Alice');
const lastName = signal('Smith');
// Automatically updates when firstName or lastName changes
const fullName = computed(() => `${firstName()} ${lastName()}`);
console.log(fullName()); // Alice Smith
firstName.set('Bob');
console.log(fullName()); // Bob Smith
import { effect } from '@angular/core';
export class AppComponent {
count = signal(0);
constructor() {
// Runs immediately and whenever count changes
effect(() => {
console.log(`Count changed to: ${this.count()}`);
// Save to localStorage, send analytics, etc.
});
}
}
@Injectable({ providedIn: 'root' })
export class ThemeService {
private _theme = signal<'light' | 'dark'>('light');
readonly theme = this._theme.asReadonly(); // expose read-only
readonly isDark = computed(() => this._theme() === 'dark');
toggle(): void {
this._theme.update(t => t === 'light' ? 'dark' : 'light');
}
}
import { input, output } from '@angular/core';
@Component({ selector: 'app-counter', standalone: true, template: `...` })
export class CounterComponent {
// Signal-based input — no more @Input decorator
initialValue = input(0);
label = input.required();
// Signal-based output
changed = output();
count = computed(() => this.initialValue());
}
All Comments