Maîtriser les Angular Signals : Une nouvelle ère pour la réactivité des composants dans Angular 17+
Angular 17+ introduit les Signals comme mécanisme de réactivité plus direct, explicite et performant. Là où les approches antérieures reposaient largement sur les Observable et des patrons parfois complexes, les Signals visent à rendre les flux de données plus simples à raisonner, tout en améliorant l’efficacité du rendu.
Cet article explique les concepts fondamentaux, les patterns recommandés, et les pratiques concrètes pour adopter les Angular Signals dans des composants et services modernes.
Pourquoi les Signals changent la donne
Les Signals fournissent un modèle réactif basé sur un graphe de dépendances. Lorsqu’une donnée signal change, les parties concernées du composant sont mises à jour de manière ciblée. Ce mécanisme réduit les recomputations inutiles et facilite la compréhension du comportement applicatif.
En pratique, les Signals combinent :
- Réactivité déclarative : la vue dépend des états réactifs, pas d’une logique impérative.
- Traçabilité des dépendances : le lien entre signaux et calculs est explicite.
- Performance : mise à jour minimale quand c’est nécessaire.
Les briques essentielles : signal, computed, effect
Créer un Signal
Un signal représente une valeur réactive. Un composant peut lire cette valeur, et la valeur peut être mise à jour via une fonction dédiée.
import { signal } from '@angular/core';
const count = signal(0);
// Lecture
const value = count();
// Mise à jour (exemple via set)
count.set(1);
Deriver une valeur : computed
Un computed dérive automatiquement une valeur à partir d’autres signaux. La recomputation n’a lieu que si les dépendances changent.
import { computed, signal } from '@angular/core';
const firstName = signal('Ada');
const lastName = signal('Lovelace');
const fullName = computed(() => `${firstName()} ${lastName()}`);
Réagir aux changements : effect
Un effect exécute une logique à chaque fois que des signaux utilisés à l’intérieur changent. Idéal pour synchroniser des effets externes (log, persistance, appel de service).
import { effect, signal } from '@angular/core';
const status = signal<'idle' | 'loading' | 'done'>('idle');
effect(() => {
const s = status();
console.log('Status:', s);
});
Signals dans les composants : patterns de base
Pour tirer parti des Signals, il est recommandé de séparer :
- État local (signals dans le composant)
- État partagé (services utilisant des signaux)
- Valeurs dérivées (computed)
- Effets (effect, ou synchronisation via des handlers)
Exemple : compteur et rendu réactif
Le rendu lit directement la valeur du signal. Quand la valeur change, Angular met à jour la vue de manière ciblée.
import { Component, computed, signal } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<strong>Count</strong> : {{ count() }}
<p>Double : {{ double() }}</p>
</div>
`
})
export class CounterComponent {
readonly count = signal(0);
readonly double = computed(() => this.count() * 2);
increment() {
this.count.update(v => v + 1);
}
}
Interagir avec des données externes
Les applications utilisent souvent des API (HTTP), des websockets ou des évènements.
Les Signals peuvent s’intégrer avec ces sources, en transformant les données en état réactif.
Approche recommandée : “source → signal”
Une stratégie robuste consiste à créer un signal qui reflète la dernière valeur issue d’un flux externe, puis à exploiter
computed/effect pour orchestrer les dépendances.
import { Injectable, signal, computed, effect } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class WeatherService {
private readonly _city = signal('Paris');
private readonly _temperature = signal(null);
readonly temperature = computed(() => this._temperature());
constructor(private http: HttpClient) {
effect(() => {
const city = this._city();
this.http
.get<{ temperature: number }>(`/api/weather?city=${encodeURIComponent(city)}`)
.subscribe(resp => this._temperature.set(resp.temperature));
});
}
setCity(name: string) {
this._city.set(name);
}
}
Signals et cycles de changement : éviter les pièges
Les Signals modifient la manière de raisonner les mises à jour.
Certains patterns doivent être maîtrisés pour éviter des comportements inattendus.
Ne pas provoquer de boucle infinie
Un effect qui déclenche une mise à jour d’un signal utilisé directement dans le même effect
peut créer une boucle. Dans ce cas, une refactorisation est souvent nécessaire :
- séparer l’état source et l’état dérivé
- utiliser computed pour la dérivation
- limiter les écritures dans effect
Choisir entre computed et effect
computed est prévu pour les valeurs dérivées “pures”.
effect est prévu pour les effets secondaires (log, requêtes, persistance).
Migration depuis Observables
Dans Angular, les Observables restent utiles (streaming, APIs RxJS riches, opérateurs).
La migration vers les Signals se fait généralement par étapes, en convertissant les sources en état réactif.
Stratégies fréquentes
- Conserver les Observables au niveau data, mais exposer des Signals au niveau UI.
- Introduire computed pour réduire la logique de mapping côté templates.
- Limiter l’usage d’effect aux synchronisations nécessaires.
Exemple de logique UI à base de Signal dérivé
// Exemple simplifié : le template dépend d’un Signal dérivé
const raw = signal<number>(10);
const formatted = computed(() => raw() + ' px');
// Le template lit formatted(), sans recalcul manuel.
Bonnes pratiques pour une adoption réussie
Centraliser l’état dans des services quand il est partagé
Les signaux partagés simplifient la cohérence entre composants.
Les services peuvent exposer des Signals (lecture) et conserver des signaux internes (écriture).
Rendre les APIs de services explicites
Un service peut exposer :
- des computed pour les valeurs prêtes à consommer
- des méthodes de mutation (ex. setCity, toggle, update)
- des signaux internes pour préserver l’encapsulation
Limiter la complexité dans les templates
Même si la lecture d’un signal dans un template est naturelle, la logique doit rester concentrée :
computed pour la transformation, effect pour les effets externes.
Checklist d’implémentation
- Définir les signaux d’état (source de vérité)
- Créer les computed (valeurs dérivées)
- Utiliser effect pour synchroniser des actions externes
- Éviter les boucles en séparant lecture et écriture
- Encapsuler les signaux dans les services si l’état est partagé
Conclusion
Les Angular Signals apportent une réactivité plus robuste, plus lisible et potentiellement plus performante.
Une adoption réussie repose sur la séparation claire entre état, dérivation et
effets, ainsi que sur une migration progressive depuis le monde Observable.
Avec ces principes, les composants Angular 17+ deviennent plus simples à maintenir et à faire évoluer.
À propos de l'auteur
Laty Gueye Samba est développeur Full Stack basé à Dakar, Sénégal.
Spécialiste des écosystèmes Java / Spring Boot et Angular.
Contact : latygueyesamba@gmail.com
| Dakar, Sénégal