Signals: Le Nouveau Standard de Reactivite qui Unit les Frameworks JavaScript
Salut HaWkers, quelque chose d'interessant se passe dans l'ecosysteme JavaScript: apres des annees ou chaque framework avait sa propre approche pour la gestion d'etat, un standard emerge - Signals.
Angular, Vue, Svelte et Solid utilisent maintenant Signals pour la reactivite. Et il y a un mouvement pour ajouter Signals directement aux specifications JavaScript.
Que Sont les Signals?
Les Signals sont des primitives de reactivite qui permettent de suivre et propager efficacement les changements d'etat. Contrairement au modele Virtual DOM utilise par React, les Signals mettent a jour uniquement les parties de l'UI qui ont reellement change.
Concepts fondamentaux:
- Signal: Un conteneur de valeur qui peut etre observe
- Computed: Une valeur derivee qui recalcule automatiquement quand ses dependances changent
- Effect: Une fonction qui s'execute automatiquement quand les Signals qu'elle utilise changent
// Exemple conceptuel de Signals
import { signal, computed, effect } from 'signals';
// Creer un signal
const count = signal(0);
// Creer une valeur computee
const doubled = computed(() => count.value * 2);
// Creer un effet
effect(() => {
console.log(`Count: ${count.value}, Doubled: ${doubled.value}`);
});
// Mettre a jour le signal - l'effet s'execute automatiquement
count.value = 5;
// Output: "Count: 5, Doubled: 10"
Pourquoi les Signals Deviennent un Standard?
1. Performance Superieure
Le modele Virtual DOM de React necessite une reconciliation de tout l'arbre de composants pour detecter les changements. Les Signals mettent a jour chirurgicalement uniquement ce qui a change.
Comparaison simplifiee:
| Approche | Quand Met a Jour | Overhead |
|---|---|---|
| Virtual DOM | Re-rend le composant entier | Eleve |
| Signals | Met a jour uniquement le binding specifique | Minimal |
2. Previsibilite
Avec les Signals, le flux de donnees est explicite. Vous savez exactement ce qui depend de quoi:
// Les dependances sont suivies automatiquement
const firstName = signal('John');
const lastName = signal('Doe');
// Ce computed depend de firstName et lastName
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
// Un changement dans firstName met a jour fullName automatiquement
firstName.value = 'Jane';
// fullName est maintenant "Jane Doe"3. Pas de Re-renders Inutiles
Dans React, tout changement d'etat peut causer un re-render de tout l'arbre de composants enfants. Avec les Signals, seuls les bindings affectes se mettent a jour.
Signals dans les Principaux Frameworks
Angular Signals
Angular a introduit les Signals dans la version 16 et c'est maintenant l'approche recommandee:
import { signal, computed, effect } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<p>Count: {{ count() }}</p>
<p>Doubled: {{ doubled() }}</p>
<button (click)="increment()">+</button>
`
})
export class CounterComponent {
count = signal(0);
doubled = computed(() => this.count() * 2);
constructor() {
effect(() => {
console.log('Count changed:', this.count());
});
}
increment() {
this.count.update(c => c + 1);
}
}Vue 3 Reactivity
Vue utilise une approche similaire avec ref et computed:
import { ref, computed, watchEffect } from 'vue';
const count = ref(0);
const doubled = computed(() => count.value * 2);
watchEffect(() => {
console.log('Count changed:', count.value);
});
// Le template utilise automatiquement
// {{ count }} et {{ doubled }}Svelte 5 Runes
Svelte 5 a introduit les "runes" - leur version des Signals:
<script>
let count = $state(0);
let doubled = $derived(count * 2);
$effect(() => {
console.log('Count changed:', count);
});
</script>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button onclick={() => count++}>+</button>SolidJS
Solid a ete pionnier de ce modele et a influence tous les autres:
import { createSignal, createEffect, createMemo } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
createEffect(() => {
console.log('Count changed:', count());
});
return (
<div>
<p>Count: {count()}</p>
<p>Doubled: {doubled()}</p>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
La Proposition TC39 pour les Signals Natifs
Il y a une proposition active au TC39 (le comite qui definit le standard JavaScript) pour ajouter les Signals nativement au langage.
Benefices des Signals natifs:
- Interoperabilite entre frameworks
- Performance optimisee par le moteur
- API standardisee
- Taille de bundle reduite (pas besoin d'importer d'une bibliotheque)
La proposition est encore a ses debuts, mais le soutien de l'industrie est fort.
A Quoi Ressembleraient les Signals Natifs?
// Syntaxe future possible (speculative)
const count = Signal.state(0);
const doubled = Signal.computed(() => count.get() * 2);
Signal.effect(() => {
console.log(`Count: ${count.get()}`);
});
count.set(5);
Et React?
React suit un chemin different avec son modele Virtual DOM et ses hooks. Le React Compiler (anciennement React Forget) vise a optimiser automatiquement les re-renders.
Position de React:
- Ne prevoit pas d'adopter les Signals dans le core
- React Compiler + Server Components est la strategie de performance
- Des bibliotheques comme Jotai et Zustand offrent des APIs similaires aux Signals
💡 Note: Vous pouvez utiliser des bibliotheques de Signals avec React, mais ce n'est pas l'approche idiomatique du framework.
Implementer les Signals depuis Zero
Pour comprendre comment ils fonctionnent, creons une version simplifiee:
// Mini implementation de Signals
let currentEffect = null;
function createSignal(initialValue) {
let value = initialValue;
const subscribers = new Set();
const read = () => {
if (currentEffect) {
subscribers.add(currentEffect);
}
return value;
};
const write = (newValue) => {
value = newValue;
subscribers.forEach(fn => fn());
};
return [read, write];
}
function createEffect(fn) {
currentEffect = fn;
fn(); // Execute pour collecter les dependances
currentEffect = null;
}
function createMemo(fn) {
const [getValue, setValue] = createSignal();
createEffect(() => {
setValue(fn());
});
return getValue;
}
// Utilisation
const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
createEffect(() => {
console.log(`Count: ${count()}, Doubled: ${doubled()}`);
});
setCount(5); // Log: "Count: 5, Doubled: 10"
Quand Utiliser les Signals vs Autres Approches
Les Signals sont ideaux pour:
- L'etat de l'UI local
- Les formulaires complexes
- Les mises a jour frequentes de petites parties de l'UI
- Les applications qui necessitent une performance maximale
D'autres approches peuvent etre meilleures pour:
- L'etat du serveur (React Query, TanStack Query)
- L'etat global tres complexe
- Les applications ou simplicite > performance
Conclusion
Les Signals representent une convergence interessante dans l'ecosysteme JavaScript. Apres des annees d'approches divergentes, les principaux frameworks adoptent un modele similaire de reactivite fine-grained.
Pour les developpeurs, cela signifie que les concepts appris dans un framework se transferent facilement aux autres. Et si la proposition TC39 est approuvee, nous pourrions avoir des Signals natifs dans JavaScript.
Si vous vous interessez aux tendances JavaScript et frameworks, je vous recommande de consulter un autre article: Pourquoi les Developpeurs Abandonnent les Frameworks et Reviennent a Vanilla JavaScript ou vous decouvrirez l'autre cote de cette discussion.

