
Mises à jour fonctionnelles pour garantir la fraîcheur de l'état
Apprenez à utiliser les mises à jour fonctionnelles de useState (setState(prevState => ...)) pour garantir la fraîcheur de l'état et éviter les bugs de stale state en React.
Le défi : Le risque de l'état obsolète (Stale State)
Lorsque vous mettez à jour l'état avec `useState`, il est courant que la nouvelle valeur dépende de la valeur précédente. Par exemple, incrémenter un compteur ou ajouter un élément à une liste. L'approche la plus directe pourrait sembler être de lire la variable d'état actuelle et de l'utiliser pour calculer la nouvelle valeur :
const [count, setCount] = useState(0);
function increment() {
// Tentative directe (peut être problématique)
setCount(count + 1);
}
Cependant, cette approche présente un risque subtil mais important. Les mises à jour d'état déclenchées par `setState` ne sont pas toujours immédiates et synchrones. React peut les regrouper (batching) pour optimiser les performances, en particulier à l'intérieur des gestionnaires d'événements. Cela signifie que si vous appelez `setCount` plusieurs fois rapidement, la variable `count` que vous lisez dans votre fonction `increment` pourrait ne pas refléter la dernière valeur d'état mise en file d'attente par React. Vous pourriez lire une valeur obsolète (stale state), conduisant à des calculs incorrects.
Imaginez un scénario où vous voulez incrémenter le compteur de 3 en un seul clic :
function incrementTroisFois() {
setCount(count + 1); // Si count vaut 0 ici...
setCount(count + 1); // ... il peut encore valoir 0 ici !
setCount(count + 1); // ... et encore 0 ici !
// Résultat potentiel : count passe à 1 au lieu de 3.
}
Dans cet exemple, si React regroupe ces trois appels, la valeur de `count` lue à chaque appel pourrait être la même (celle avant le début du batch), annulant l'effet des incrémentations précédentes dans la même passe.
La solution : La forme fonctionnelle de mise à jour
Pour résoudre ce problème et garantir que vos mises à jour se basent toujours sur la valeur la plus récente de l'état, `useState` propose une syntaxe alternative pour sa fonction de mise à jour : la forme fonctionnelle.
Au lieu de passer directement la nouvelle valeur, vous passez une fonction. Cette fonction recevra automatiquement l'état précédent (garanti comme étant le plus à jour au moment de l'exécution de la mise à jour par React) comme argument. La valeur retournée par cette fonction deviendra le nouvel état.
La syntaxe est la suivante :
setEtat(prevState => {
// Calculer le nouvel état basé sur prevState
const newState = /* ... logique utilisant prevState ... */;
return newState;
});
// Version concise pour des calculs simples
setEtat(prevState => prevState + 1);
Reprenons notre exemple d'incrémentation triple, cette fois avec la forme fonctionnelle :
function incrementTroisFoisCorrectement() {
setCount(prevCount => prevCount + 1); // Reçoit la dernière valeur (0), retourne 1
setCount(prevCount => prevCount + 1); // Reçoit la dernière valeur (1), retourne 2
setCount(prevCount => prevCount + 1); // Reçoit la dernière valeur (2), retourne 3
// Résultat garanti : count passe bien à 3.
}
Avec cette approche, même si React regroupe les mises à jour, chaque appel à la fonction de mise à jour recevra comme `prevCount` la valeur résultant de la mise à jour précédente dans la file d'attente. Cela garantit la correction du calcul, indépendamment du timing ou du batching des mises à jour.
Pourquoi et quand utiliser les mises à jour fonctionnelles ?
Il est fortement recommandé d'utiliser la forme fonctionnelle de mise à jour chaque fois que le nouvel état dépend de l'état précédent.
Les avantages principaux sont :
- Fiabilité : Elimine les bugs liés au "stale state" causés par les mises à jour asynchrones ou groupées. Vous êtes certain de travailler avec la valeur d'état la plus récente au moment du calcul.
- Prévisibilité : Le comportement de vos mises à jour d'état devient plus prévisible, indépendamment des optimisations internes de React.
- Robustesse : Votre code est moins susceptible de casser si la logique de mise à jour devient plus complexe ou si elle est appelée dans des contextes où le batching est plus fréquent.
Même si dans certains cas simples, la mise à jour directe peut sembler fonctionner, prendre l'habitude d'utiliser la forme fonctionnelle pour les mises à jour dépendantes de l'état précédent est une bonne pratique qui renforce la robustesse de vos composants React.