Reactivity
Signals & fine-grained reactivity
Writable/computed signals, effects, and how they change detection.
Signals are a synchronous reactivity primitive: a signal() holds state, a computed() derives from signals and memoizes, and an effect() re-runs when its read signals change. Reading a signal in a template registers a fine-grained dependency.
Signals turn your app into a spreadsheet: change one cell and only the dependent formulas recalculate — not the entire sheet.
Key concepts
1
This lets Angular update only the specific views that read a changed signal, moving the framework toward zoneless change detection and away from checking the whole tree.
zoneless
2
Signals vs observables: signals are synchronous, always have a current value, and model state; observables model asynchronous streams over time. Interop exists both ways (toSignal, toObservable).
Signals vs observables:toSignaltoObservable
3
Pitfall: writing to a signal inside a computed (computeds must be pure) or creating effects that write signals and cause loops. Interview angle: "when would you pick a signal over a BehaviorSubject?" — synchronous derived state and template-driven fine-grained updates.
Pitfall:Interview angle:computed
typescript
@Component({ /* ... */ })
export class CartComponent {
readonly items = signal<Item[]>([]);
readonly total = computed(() => this.items().reduce((s, i) => s + i.price, 0));
readonly count = computed(() => this.items().length);
add(item: Item) { this.items.update(list => [...list, item]); }
constructor() { effect(() => console.log('cart total', this.total())); }
}