A Deep Dive into Angular Signals: Writable, Readable Signals, Zone.js, and RxJS

Anil Verma
3 min readDec 18, 2024

--

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 of 0.
  • 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 the firstName and lastName 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……👏👏👏

--

--

Anil Verma
Anil Verma

Written by Anil Verma

Hi there 👋, I am Anil Verma, a full stack web developer, and JavaScript enthusiast. 👥 Ask me anything about web development. web- https://anilvermaspeaks.in/

No responses yet