What are Signals?
A Signal is a wrapper around a value that notifies consumers when that value changes. Unlike RxJS Observables, which are streams of data that require subscriptions, Signals are synchronous and 'glitch-free'. As an Architect, you should view Signals as the primary way to manage local and shared state in modern Angular apps. They enable 'Zoneless' applications, where Angular no longer relies on Zone.js to detect changes, leading to massive performance gains and smaller bundle sizes.
- The Three Core Primitives
There are three primary functions that make up the Signals API.
- signal(): Creates a 'Writable Signal'. You can change its value directly using
.set()or.update(). - computed(): Creates a read-only signal that derives its value from other signals. It is lazily evaluated and memoized (it only re-calculates if its dependencies change).
- effect(): A function that runs whenever the signals it reads change. Use this for side effects like logging, manual DOM manipulation, or syncing with LocalStorage.
- Basic Implementation
In your component, you define a signal and call it as a function in your template to read its current value. Angular automatically tracks this dependency.
- Signals vs. RxJS
As a Lead, it's important to know when to use which. Signals are for State (values over time), while RxJS is for Events and Asynchronous Streams (API calls, web sockets, complex timing).
| Feature | Signals | RxJS Observables |
|---|---|---|
| Nature | Synchronous / State | Asynchronous / Streams |
| Consumer | Functional call: count() | Subscription: .subscribe() |
| Cleanup | Automatic | Manual (Unsubscribe) |
| Performance | Fine-grained (targeted) | Coarse-grained (Zone.js) |
| Best For | Local state, derived values | HTTP calls, Event logic |
Reactivity Evolution
Signals represent a shift from 'Push-based' (RxJS) to 'Producer-Consumer' based reactivity, reducing the complexity of the change detection cycle.