Signals est une bibliothèque de gestion de l'État performant avec deux objectifs principaux:
Lisez le post d'annonce pour en savoir plus sur les problèmes que les signaux résout et comment il est arrivé.
# Just the core library
npm install @preact/signals-core
# If you're using Preact
npm install @preact/signals
# If you're using React
npm install @preact/signals-react
# If you're using Svelte
npm install @preact/signals-core
signal(initialValue)
signal.peek()
computed(fn)
effect(fn)
batch(fn)
untracked(fn)
La bibliothèque de signaux expose quatre fonctions qui sont les éléments constitutifs pour modéliser toute logique métier à laquelle vous pouvez penser.
signal(initialValue)
La fonction signal
crée un nouveau signal. Un signal est un conteneur pour une valeur qui peut changer avec le temps. Vous pouvez lire la valeur d'un signal ou vous abonner aux mises à jour de valeur en accédant à sa propriété .value
.
import { signal } from "@preact/signals-core" ;
const counter = signal ( 0 ) ;
// Read value from signal, logs: 0
console . log ( counter . value ) ;
// Write to a signal
counter . value = 1 ;
L'écriture sur un signal est effectuée en définissant sa propriété .value
. La modification de la valeur d'un signal met à jour de manière synchrone chaque calcul et effet qui dépend de ce signal, garantissant que votre état d'application est toujours cohérent.
signal.peek()
Dans les rares cas où vous avez un effet qui devrait écrire à un autre signal en fonction de la valeur précédente, mais vous ne voulez pas que l'effet soit abonné à ce signal, vous pouvez lire la valeur précédente d'une signaux via signal.peek()
.
const counter = signal ( 0 ) ;
const effectCount = signal ( 0 ) ;
effect ( ( ) => {
console . log ( counter . value ) ;
// Whenever this effect is triggered, increase `effectCount`.
// But we don't want this signal to react to `effectCount`
effectCount . value = effectCount . peek ( ) + 1 ;
} ) ;
Notez que vous ne devez utiliser signal.peek()
que si vous en avez vraiment besoin. La lecture de la valeur d'un signal via signal.value
est la manière préférée dans la plupart des scénarios.
computed(fn)
Les données sont souvent dérivées d'autres éléments de données existantes. La fonction computed
vous permet de combiner les valeurs de plusieurs signaux dans un nouveau signal qui peut être réagi, ou même utilisé par des calculs supplémentaires. Lorsque les signaux accessibles à partir d'un changement de rappel calculé, le rappel calculé est réexécuté et sa nouvelle valeur de retour devient la valeur du signal calculé.
import { signal , computed } from "@preact/signals-core" ;
const name = signal ( "Jane" ) ;
const surname = signal ( "Doe" ) ;
const fullName = computed ( ( ) => name . value + " " + surname . value ) ;
// Logs: "Jane Doe"
console . log ( fullName . value ) ;
// Updates flow through computed, but only if someone
// subscribes to it. More on that later.
name . value = "John" ;
// Logs: "John Doe"
console . log ( fullName . value ) ;
Tout signal accessible à l'intérieur de la fonction de rappel du computed
sera automatiquement abonné et suivi comme une dépendance du signal calculé.
effect(fn)
La fonction effect
est la dernière pièce qui rend tout réactif. Lorsque vous accédez à un signal à l'intérieur de sa fonction de rappel, ce signal et chaque dépendance dudit signal seront activés et abonnés. À cet égard, il est très similaire à computed(fn)
. Par défaut, toutes les mises à jour sont paresseuses, donc rien ne mettra à jour jusqu'à ce que vous accédez à un signal à l'intérieur effect
.
import { signal , computed , effect } from "@preact/signals-core" ;
const name = signal ( "Jane" ) ;
const surname = signal ( "Doe" ) ;
const fullName = computed ( ( ) => name . value + " " + surname . value ) ;
// Logs: "Jane Doe"
effect ( ( ) => console . log ( fullName . value ) ) ;
// Updating one of its dependencies will automatically trigger
// the effect above, and will print "John Doe" to the console.
name . value = "John" ;
Vous pouvez détruire un effet et vous désinscrire de tous les signaux auxquels il a été abonné, en appelant la fonction retournée.
import { signal , computed , effect } from "@preact/signals-core" ;
const name = signal ( "Jane" ) ;
const surname = signal ( "Doe" ) ;
const fullName = computed ( ( ) => name . value + " " + surname . value ) ;
// Logs: "Jane Doe"
const dispose = effect ( ( ) => console . log ( fullName . value ) ) ;
// Destroy effect and subscriptions
dispose ( ) ;
// Update does nothing, because no one is subscribed anymore.
// Even the computed `fullName` signal won't change, because it knows
// that no one listens to it.
surname . value = "Doe 2" ;
Le rappel d'effet peut renvoyer une fonction de nettoyage. La fonction de nettoyage est exécutée une fois, soit lorsque le rappel d'effet est appelé suivant , soit lorsque l'effet est éliminé, selon la première éventualité.
import { signal , effect } from "@preact/signals-core" ;
const count = signal ( 0 ) ;
const dispose = effect ( ( ) => {
const c = count . value ;
return ( ) => console . log ( `cleanup ${ c } ` ) ;
} ) ;
// Logs: cleanup 0
count . value = 1 ;
// Logs: cleanup 1
dispose ( ) ;
batch(fn)
La fonction batch
vous permet de combiner plusieurs écritures de signaux en une seule mise à jour qui est déclenchée à la fin à la fin du rappel.
import { signal , computed , effect , batch } from "@preact/signals-core" ;
const name = signal ( "Jane" ) ;
const surname = signal ( "Doe" ) ;
const fullName = computed ( ( ) => name . value + " " + surname . value ) ;
// Logs: "Jane Doe"
effect ( ( ) => console . log ( fullName . value ) ) ;
// Combines both signal writes into one update. Once the callback
// returns the `effect` will trigger and we'll log "Foo Bar"
batch ( ( ) => {
name . value = "Foo" ;
surname . value = "Bar" ;
} ) ;
Lorsque vous accédez à un signal auquel vous avez écrit plus tôt dans le rappel ou accéder à un signal calculé qui a été invalidé par un autre signal, nous ne mettrons à jour que les dépendances nécessaires pour obtenir la valeur actuelle du signal que vous avez lu. Tous les autres signaux non validés se mettront à jour à la fin de la fonction de rappel.
import { signal , computed , effect , batch } from "@preact/signals-core" ;
const counter = signal ( 0 ) ;
const double = computed ( ( ) => counter . value * 2 ) ;
const triple = computed ( ( ) => counter . value * 3 ) ;
effect ( ( ) => console . log ( double . value , triple . value ) ) ;
batch ( ( ) => {
counter . value = 1 ;
// Logs: 2, despite being inside batch, but `triple`
// will only update once the callback is complete
console . log ( double . value ) ;
} ) ;
// Now we reached the end of the batch and call the effect
Les lots peuvent être imbriqués et les mises à jour seront rincées lorsque l'appel par lots le plus extérieur se termine.
import { signal , computed , effect , batch } from "@preact/signals-core" ;
const counter = signal ( 0 ) ;
effect ( ( ) => console . log ( counter . value ) ) ;
batch ( ( ) => {
batch ( ( ) => {
// Signal is invalidated, but update is not flushed because
// we're still inside another batch
counter . value = 1 ;
} ) ;
// Still not updated...
} ) ;
// Now the callback completed and we'll trigger the effect.
untracked(fn)
Dans le cas où lorsque vous recevez un rappel qui peut lire certains signaux, mais que vous ne voulez pas vous abonner, vous pouvez utiliser untracked
pour empêcher que les abonnements ne se produisent.
const counter = signal ( 0 ) ;
const effectCount = signal ( 0 ) ;
const fn = ( ) => effectCount . value + 1 ;
effect ( ( ) => {
console . log ( counter . value ) ;
// Whenever this effect is triggered, run `fn` that gives new value
effectCount . value = untracked ( fn ) ;
} ) ;
MIT
, voir le fichier de licence.