
Alternative à `useState` pour une logique d'état plus complexe
Explorez les raisons d'utiliser le hook useReducer comme alternative à useState en React lorsque la logique de gestion d'état devient complexe ou interdépendante.
La simplicité de `useState` et ses limites
Le hook `useState` est l'outil de base pour introduire de l'état dans les composants fonctionnels React. Sa simplicité est son grand avantage : const [valeur, setValeur] = useState(initial); est facile à comprendre et à utiliser pour des cas simples comme gérer l'état d'un booléen (un interrupteur on/off), une chaîne de caractères (la valeur d'un champ de texte), ou un nombre (un compteur).
Cependant, cette simplicité peut devenir une faiblesse lorsque la logique de gestion de l'état se complexifie. Imaginez un composant qui doit gérer plusieurs pièces d'information interdépendantes, ou dont les mises à jour suivent des règles précises basées sur l'état précédent et l'action déclenchée. Dans de tels scénarios, utiliser plusieurs appels à `useState` peut entraîner plusieurs problèmes :
Scénarios où `useState` devient complexe
- Multiples états liés : Si vous avez plusieurs variables d'état qui doivent être mises à jour ensemble ou dont les valeurs dépendent les unes des autres (par exemple, un état de chargement, les données elles-mêmes, et un état d'erreur pour une requête API), vous vous retrouvez avec de multiples appels
set...souvent regroupés, ce qui peut être source d'erreurs si une mise à jour est oubliée. - Logique de mise à jour complexe : Lorsque la nouvelle valeur de l'état ne dépend pas seulement de la valeur précédente de manière simple (comme `count + 1`), mais implique des conditions, des calculs basés sur plusieurs parties de l'état, ou des transitions spécifiques. Placer cette logique complexe directement dans les gestionnaires d'événements rend le code difficile à lire et à tester.
// Exemple : Logique complexe dans un gestionnaire avec useState
function handleComplexAction(payload) {
if (isLoading) return; // Dépend de l'état isLoading
setIsLoading(true); // Mise à jour état 1
setError(null); // Mise à jour état 2
performAction(data, payload) // Dépend de l'état data
.then(newData => {
setData(newData); // Mise à jour état 3
})
.catch(err => {
setError(err); // Mise à jour état 2 (encore)
})
.finally(() => {
setIsLoading(false); // Mise à jour état 1 (encore)
});
}
// La logique de transition est éparpillée et liée à l'événement.
`useReducer` : Centraliser et structurer la complexité
C'est précisément pour pallier ces difficultés que `useReducer` a été introduit comme une alternative à `useState`. Il ne remplace pas `useState` pour les cas simples, mais offre une approche plus structurée lorsque la logique d'état devient non triviale.
L'idée maîtresse de `useReducer` est de centraliser toute la logique de mise à jour de l'état dans une seule fonction : le reducer. Au lieu d'appeler différentes fonctions `set...` depuis divers endroits, vous appelez une seule fonction `dispatch` en lui passant une "action" qui décrit ce qui doit se passer. C'est ensuite le reducer qui interprète cette action et détermine, en fonction de l'état actuel, quel doit être le nouvel état.
Cette séparation entre la description de la mise à jour (l'action envoyée via `dispatch`) et la logique de la mise à jour (le reducer) apporte plusieurs avantages lorsque la complexité augmente :
- Clarté : Toute la logique de transition d'état est regroupée au même endroit (le reducer).
- Prévisibilité : Il est plus facile de suivre comment l'état peut changer car toutes les modifications passent par le reducer.
- Maintenance : Modifier la logique d'état se fait en un seul endroit.
- Testabilité : Le reducer est une fonction pure, facilement testable indépendamment du composant React.
Quand envisager `useReducer` ?
Il n'y a pas de règle absolue, mais voici de bons indicateurs qu'il est peut-être temps de passer de `useState` à `useReducer` :
- Vous avez plusieurs variables d'état qui sont souvent mises à jour ensemble ou dont les logiques sont liées.
- La logique de mise à jour pour passer d'un état à un autre est complexe (implique des conditions, dépend fortement de l'état précédent).
- Vous vous retrouvez à écrire des logiques similaires dans plusieurs gestionnaires d'événements pour mettre à jour l'état.
- Vous souhaitez améliorer la testabilité de votre logique d'état.
- La taille de votre composant augmente et vous voulez mieux séparer la logique d'état de la logique de rendu.
- Vous gérez un état qui peut être vu comme une "machine à états" avec des transitions bien définies.
En résumé, `useReducer` brille lorsque la relation entre les différentes pièces de l'état ou la complexité des transitions d'état rend la gestion via `useState` moins lisible, moins maintenable ou plus sujette aux erreurs. C'est l'outil de choix pour structurer la complexité de l'état local.