A Deep Dive into Angular Signals: Writable, Readable Signals, Zone.js, and RxJS
New reactive programming paradigm aimed at simplifying state management within Angular applications
What Are Angular Signals?
At their core, Angular signals are a new reactive programming paradigm aimed at simplifying state management within Angular applications. They are reactive values that automatically update when their dependencies change, but with a more straightforward and lightweight syntax than using traditional RxJS observables. Signals can be either writable or readable, and they are used to manage state in a more declarative way.
- Writable signals allow you to mutate state, meaning you can both read and write to the signal.
- Readable signals are immutable — you can only read the value, which is usually computed based on other signals or external data sources.
Why Signals?
While RxJS provides a powerful mechanism for handling state and events in Angular, it comes with its own complexity and learning curve. Angular signals offer a simpler alternative, allowing for more intuitive state management with fewer abstractions. You no longer need to manage subscriptions and operators like map()
, filter()
, and mergeMap()
. Instead, signals give you direct access to state changes, making reactivity more explicit and easier to handle.
How Signals Improve Change Detection
Unlike Zone.js-based change detection, Angular signals have fine-grained reactivity. This means that Angular only reacts to changes in the specific signals you are working with, not all async operations globally. Signals don’t require Zone.js to track every asynchronous event — instead, Angular uses smart subscriptions to trigger updates only when relevant signals change.
In simpler terms, when a writable signal updates, Angular knows exactly where the change occurred, and it re-renders only the components or parts of the template that are directly dependent on that signal. This makes it possible to achieve more efficient change detection and avoids unnecessary re-renders that can happen with Zone.js.
Creating and Using Writable Signals
Writable signals are created using the signal()
function, which allows you to define an initial value. You can then use the .set()
method to modify the value of the signal, and the signal’s new value will automatically propagate through the app.
import { Component } from '@angular/core';
import { signal } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<div>
<p>Counter: {{ counter() }}</p>
<button (click)="increment()">Increment</button>
<button (click)="decrement()">Decrement</button>
</div>
`,
})
export class CounterComponent {
counter = signal(0); // Writable signal
increment() {
this.counter.set(this.counter() + 1);
}
decrement() {
this.counter.set(this.counter() - 1);
}
}
- We create a writable signal
counter
with an initial value of0
. - When the increment or decrement buttons are clicked, we modify the signal using the
.set()
method. - The component’s view automatically reflects the updated value without requiring manual subscriptions or change detection triggers.
Readable Signals: Immutable State in Angular
Readable signals are used to store immutable values that cannot be changed directly. These signals are computed or derived from other signals, making them ideal for cases where you want to expose a value that depends on other parts of the state.
import { Component } from '@angular/core';
import { signal } from '@angular/core';
@Component({
selector: 'app-user',
template: `
<div>
<p>Full Name: {{ fullName() }}</p>
</div>
`,
})
export class UserComponent {
firstName = signal('John');
lastName = signal('Doe');
fullName = signal(() => `${this.firstName()} ${this.lastName()}`); // Readable signal
}
fullName
is a readable signal that computes its value based on thefirstName
andlastName
signals.- The
fullName
signal can’t be changed directly — it’s always derived from the other two signals.
Writable Signals
- Mutable state — can be modified using the
.set() or .update()
method. - Ideal for local component state or global state that needs to change over time.
Readable Signals
- Immutable state — cannot be modified directly.
- Ideal for computed values or derived state that depends on other signals.
Zone.js vs Signals
- Zone.js is best suited for scenarios where you need to handle global asynchronous events (like HTTP requests, timers, etc.) and automatically trigger change detection across the entire app.
- Signals offer fine-grained reactivity, allowing Angular to react only to specific changes. Signals are much more efficient and predictable for local state management within a component or service.
RxJS vs Signals
- RxJS is still incredibly powerful for handling complex asynchronous streams, event handling, and multi-step data flows.
- Signals, on the other hand, offer a simpler, more declarative approach for managing state that needs to update reactively. Signals don’t replace RxJS; they complement it for local state and derived state.
Happy Learning……👏👏👏