State Management
Priority: P1 (HIGH)
1. Use Signals for All State
- Keep internal signals private; expose publicly via
asReadonly().
See signal store pattern for signal-based service and store examples.
2. Derive State with computed()
- Use
computed()for totals, filtered lists, and other derived values — it is pure and cached. - Use
linkedSignal(() => source())for dependent writable state that resets when source changes. - Use
untracked()to read a signal insidecomputed()/effect()without creating a dependency.
3. Scale with Signal Store
- For complex features, use
@ngrx/signals(signalStore) withwithState,withComputed,withMethods, andwithEntities().
4. Handle Side Effects
- Use
effect()only for side effects (logging, localStorage sync, DOM manipulation). - Never update signals inside effect() — causes circular dependencies.
- Treat signal values as immutable — update with
.set()or.update(v => ...).
Anti-Patterns
- No state logic in components: Delegate to a Signal Store or Service.
- No
BehaviorSubjectfor state: Use Signals; keep RxJS only for complex event streams.