
L'état dans les composants classe (`this.state`, `this.setState`) - Comparaison
Comparez la gestion de l'état dans les composants fonctionnels (useState) et les composants classe (this.state, this.setState). Comprenez l'approche historique.
L'approche historique de la gestion d'état
Avant l'introduction des Hooks et de `useState`, la seule manière de gérer un état local dans React était d'utiliser les composants classe. Ils possédaient des mécanismes intégrés spécifiquement conçus pour cela : la propriété `this.state` pour stocker l'état et la méthode `this.setState()` pour le mettre à jour.
Bien que `useState` soit aujourd'hui la méthode privilégiée pour les composants fonctionnels, comprendre comment l'état fonctionne dans les composants classe reste essentiel pour travailler avec des bases de code plus anciennes ou pour saisir l'évolution de React. Cette section détaille ce mécanisme et le compare à l'approche `useState`.
Initialisation de l'état : Le `constructor` et `this.state`
Dans un composant classe, l'état doit être initialisé dans le `constructor` de la classe. C'est la seule fois où vous êtes autorisé à assigner directement une valeur à `this.state`. L'état doit toujours être un objet.
import React from 'react';
class CompteurClasse extends React.Component {
constructor(props) {
super(props); // Appel obligatoire du constructeur parent
// Initialisation directe de this.state avec un objet
this.state = {
compte: 0, // Propriété 'compte' de l'état
nom: 'Compteur Initial'
};
}
// ... reste de la classe
}Comparaison avec `useState` :
- `useState` : L'initialisation se fait directement via l'argument passé à `useState(valeurInitiale)`. La valeur initiale peut être de n'importe quel type (nombre, chaîne, objet, tableau...).
- `this.state` : L'initialisation se fait dans le `constructor` en assignant un objet à `this.state`. L'état global est toujours un objet, même si vous ne suivez qu'une seule valeur (qui serait une propriété de cet objet).
Lecture de l'état : `this.state`
Pour lire la valeur actuelle d'une propriété de l'état dans un composant classe, vous utilisez la notation pointée sur l'objet `this.state`.
class CompteurClasse extends React.Component {
constructor(props) {
super(props);
this.state = { compte: 0, nom: 'Mon Compteur' };
}
render() {
return (
{/* Lecture des propriétés de l'état via this.state */}
{this.state.nom}
Le compte est à : {this.state.compte}
{/* ... boutons ... */}
);
}
}Comparaison avec `useState` :
- `useState` : La valeur actuelle est directement disponible dans la première variable retournée par la déstructuration (`const [compte, ...] = useState(0);` -> utiliser `compte`).
- `this.state` : Il faut passer par `this.state` puis le nom de la propriété (`this.state.compte`).
Mise à jour de l'état : La méthode `this.setState()`
C'est la différence la plus significative. Pour mettre à jour l'état dans un composant classe et déclencher un re-rendu, vous devez impérativement utiliser la méthode `this.setState()`. Ne modifiez jamais `this.state` directement après l'initialisation.
`this.setState()` prend généralement un objet en argument. Cet objet contient les propriétés de l'état que vous souhaitez modifier. React effectue une fusion superficielle (shallow merge) : il met à jour uniquement les propriétés spécifiées dans l'objet passé à `setState` et laisse les autres propriétés de `this.state` inchangées.
class CompteurClasse extends React.Component {
constructor(props) {
super(props);
this.state = { compte: 0, nom: 'Mon Compteur' };
// Binding nécessaire si 'incrementer' n'est pas une fonction fléchée de classe
// this.incrementer = this.incrementer.bind(this);
}
// Utilisation d'une fonction fléchée pour éviter les problèmes de 'this'
incrementer = () => {
// Appel à this.setState avec un objet pour mettre à jour 'compte'
this.setState({ compte: this.state.compte + 1 });
// La propriété 'nom' de this.state n'est pas affectée par cet appel.
}
// Méthode pour changer le nom (exemple)
changerNom = () => {
this.setState({ nom: 'Compteur Mis à Jour' });
// La propriété 'compte' n'est pas affectée.
}
render() {
// ... (lecture de this.state.nom et this.state.compte)
return (
{this.state.nom}
Le compte est à : {this.state.compte}
);
}
}Comparaison avec `useState` :
- `useState` (Setter) : La fonction setter (`setEtat`) remplace entièrement l'ancienne valeur de l'état. Si l'état est un objet, vous devez explicitement inclure toutes les propriétés (souvent en utilisant le spread operator `...`) pour ne pas perdre les autres.
- `this.setState()` : Effectue une fusion superficielle. Vous ne spécifiez que les parties de l'objet `this.state` que vous voulez changer. C'est pratique quand l'état est un objet avec plusieurs propriétés indépendantes.
Mise à jour basée sur l'état précédent (Forme fonctionnelle de `setState`)
Tout comme le setter de `useState`, `this.setState()` accepte également une forme fonctionnelle pour gérer les mises à jour dépendant de l'état précédent et éviter les problèmes liés à l'asynchronisme. Cette fonction reçoit l'état précédent (`prevState`) et les props actuelles (`props`) comme arguments.
incrementerFiable = () => {
// Utilisation de la forme fonctionnelle de setState
this.setState((prevState, props) => {
// Calcule et retourne un objet contenant les changements
return { compte: prevState.compte + 1 };
});
}
incrementerTroisFoisFiable = () => {
this.setState((prevState) => ({ compte: prevState.compte + 1 }));
this.setState((prevState) => ({ compte: prevState.compte + 1 }));
this.setState((prevState) => ({ compte: prevState.compte + 1 }));
// Ceci fonctionnera correctement et incrémentera de 3.
}Comparaison avec `useState` :
- `useState` (Setter fonctionnel) : `setEtat(prevState => newState)`. Reçoit uniquement l'état précédent.
- `this.setState` (Fonctionnel) : `this.setState((prevState, props) => ({ partialStateUpdate }))`. Reçoit l'état précédent et les props actuelles. Retourne un objet partiel qui sera fusionné.
Synthèse de la comparaison
- Initialisation : `useState(val)` vs `constructor() { this.state = {} }`
- Lecture : Variable directe vs `this.state.prop`
- Mise à jour : `setEtat(newVal)` (remplace) ou `setEtat(fn)` vs `this.setState({partial})` (fusionne) ou `this.setState(fn)`
- Types d'état : `useState` gère n'importe quel type ; `this.state` est toujours un objet.
- Multiples états : Plusieurs `useState` vs un seul `this.state` (avec plusieurs propriétés).
- Syntaxe/`this` : `useState` évite les complexités liées au `this` des classes.
Conclusion : Comprendre l'héritage, privilégier le moderne
La gestion de l'état avec `this.state` et `this.setState()` dans les composants classe était le pilier de l'interactivité React pendant des années. Ses mécanismes de fusion superficielle et sa forme fonctionnelle pour les mises à jour fiables sont des concepts importants à connaître pour travailler avec du code existant.
Cependant, la comparaison met en lumière la simplicité et la flexibilité apportées par le Hook `useState` dans les composants fonctionnels : gestion directe de n'importe quel type de donnée, multiples états indépendants faciles à déclarer, et absence des complexités liées au `this`. C'est pourquoi `useState` est l'approche standard et recommandée pour la gestion de l'état local dans le développement React moderne.