Angular Signals - Quick introduction

When to use Signals. Are they better than RxJS?

Angular signals, the synchronous reactivity

Signals help the developer to handle the state of the application allowing Angular to optimize the rendering updates.
They are wrappers around values that communicate to consumers the state change.

Signals :

  • impact the change detection in Angular
  • allows to communicate to the template that the data has changed
  • add reactivity to the code, reducing the need for RxJS

Here an example of initialization:

const firstValue = signal(12.23); // or const firstValue : WritableSignal<number> = signal(12.23);
const secondValue = signal(23.23);
const sum = computed(()=>firstValue() + secondValue())

firstValue.set(0);
// automatically recalculate sum -> sum() => 23.23

signals are getter functions

firstValue() means the the value of firstValue
.set() changes the value for a writable signal
.update() compute a new value from the previous one:
firstValue.update(previousValue=> previousValue *2)

computed signal

It derives his value from other signals, it's not writable. It's lazy calculated. When one of the values computed changes, it is flagged for recalculation. Next time it will read, it will be recalculated.

In OnPush components, the update signal will marks the component for update.

fullName = computed(() => `${this.firstName()} ${this.familyName()}`);

and in the template:

Welcome, {{fullName()}}

signal as input - from 17.1.1

Signals can be declared as @Input() without an explicit decorator.

You can for example:

  firstName = input<string>();            // string|undefined
  lastName = input.required<string>();    // string mandatory
  age = input(0);                         // number with default value
  year: InputSignal<any,number> = input() // explicit declaration

In the HTML you can use the signals:

<app-input-signals
        [firstName]="'Marco'"
        [lastName]="'Molteni'"
        [year]="2024" ></app-input-signals>

You can pass parameters to input, e.g.:

city = input<string|undefined>(undefined, {alias: 'locality'})

effects (developer preview)

Consumers can be notified when signals values change.

constructor() {
	effect(() => {
	console.log(this.firstName());
	})
}

With this code a message will be logged every time the value (this.firstName) will change.

Effects are executed at least once and are asynchronous.
The Angular team don't recommend effects for propagation of state changes.

The effect requires the injection of a context, for this reason it can be created:

  • in the constructor
  • assigned to a field
    or passing the injector in the properties: effect(() =>{...}, {injector: this.injector});

Should I use signals for every property?

No, only states that will change and will be reflected in the UI (template).

Advantages compared to RxJS

Signals have functionalities that can be replicated with RxJS operators.

signal(), compute() and effects() have similar features to RxJS Subscriptions and Observables, their big advantage is that they don't require any subscription to access the value ... so they are easier to implement.
They are destroyed automatically, so signal don't require an unsubscribe, reducing memory risks in the implementation.

With some potential advantages linked to the caching mechanism and signals doesn't use zone.js

When to use signals and when to use RxJS

The 2 are reactive with a big difference that :

  • signals are synchronous
  • rxjs is asynchronous

For this reason signals are not a replacement for RxJS! If you are waiting for an undetermined (in quantity or time) event, you have to continue to use RxJS. If the event is determined and can be synchronous, signals could reduce the complexity of your code.

The long term goal of the Angular team is to make RxJS optional. This is a step in that direction.

https://angular.io/guide/signals