useState : ce que c'est, le hook d'état et la syntaxe dans React

Auteur : IT Sectr Publié le : 2026-07-04 Temps de lecture : 9 min

useState est un Hook intégré de React qui permet aux composants fonctionnels de gérer un état local sans avoir à les convertir en composants de classe. React 16.8 a introduit les Hooks, et useState est devenu le plus utilisé parmi eux, remplaçant this.state et this.setState de l'approche basée sur les classes. Selon la Documentation React (2025), plus de 80% des composants dans les applications React modernes utilisent useState pour gérer les données de formulaire, les indicateurs d'interface et les compteurs. Le Hook retourne un tuple composé de la valeur actuelle et d'une fonction setter qui met à jour l'état et déclenche un nouveau rendu du composant.

Points clés

  • useState « un Hook pour gérer l'état local dans les composants fonctionnels React.
  • Tuple « retourne une paire [valeur, setter], où setter est une fonction de mise à jour de l'état.
  • Nouveau rendu « l'appel du setter déclenche toujours un nouveau rendu du composant avec la nouvelle valeur.
  • Types de données « useState fonctionne avec les nombres, chaînes, tableaux, objets et valeurs booléennes.
  • Immutabilité « l'état ne peut pas être muté directement, seulement via la fonction setter.

Qu'est-ce que useState dans React

useState est un Hook fondamental de React, ajouté dans la version 16.8, qui donne aux composants fonctionnels la capacité de stocker et de modifier un état local. Avant l'introduction des Hooks, l'état ne pouvait être utilisé que dans les composants de classe via this.state et this.setState, ce qui rendait les composants fonctionnels purement destinés à la présentation. useState a supprimé cette limitation, permettant d'écrire des applications entières en utilisant des composants fonctionnels.

Le Hook prend un argument « la valeur initiale de l'état « et retourne un tableau de deux éléments. Le premier élément est la valeur actuelle de l'état, le second est une fonction pour le mettre à jour. React garantit que la fonction setter est stable et ne change pas entre les rendus, ce qui permet de la passer en toute sécurité aux composants enfants et de l'utiliser dans les fermetures.

Selon l'Enquête d'utilisation de React DevTools (2024), useState est utilisé dans 96% des applications React, ce qui en fait le Hook le plus courant dans l'écosystème. Même dans les applications utilisant un état global via Redux ou Zustand, l'état local via useState reste le mécanisme principal de gestion de l'état de l'interface utilisateur « modales ouvertes, valeurs de champs de saisie, onglets actifs.

jsx
import { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>
                Increment
            </button>
        </div>
    );
}

Comment fonctionne useState

Le mécanisme interne de useState est basé sur le système de nœuds fiber de React. Chaque composant dans React est représenté par un nœud fiber qui stocke une liste chaînée des Hooks qui lui sont associés. Lorsqu'un composant appelle useState, React crée un nouveau nœud dans cette liste et y stocke la valeur actuelle de l'état ainsi qu'une référence à la file d'attente des mises à jour.

Lorsque la fonction setter est appelée, React ne met pas à jour l'état immédiatement. Au lieu de cela, il place la mise à jour dans une file d'attente d'état en attente, planifie un nouveau rendu du composant et ne calcule le nouvel état que lors du rendu suivant, sur la base de l'ancien état et des mises à jour appliquées. Cela garantit le regroupement par lots « si vous appelez le setter trois fois dans un même gestionnaire d'événement, React les regroupe en un seul nouveau rendu.

Selon le Groupe de travail React 18 « Équipe React (2024), le regroupement automatique a été étendu dans React 18 : les mises à jour d'état sont désormais regroupées non seulement dans les gestionnaires d'événements, mais aussi dans setTimeout, les callbacks Promise et les gestionnaires d'événements natifs. Cela a apporté un gain de performances allant jusqu'à 30% dans les scénarios avec plusieurs mises à jour d'état.

Mise à jour fonctionnelle de l'état

Lorsque le nouvel état dépend du précédent, utilisez la forme fonctionnelle du setter : setCount(prev => prev + 1). React transmet à la fonction la valeur réelle de l'état au moment de la mise à jour, garantissant ainsi la correction même avec des mises à jour groupées. Sans la forme fonctionnelle, setCount(count + 1) peut utiliser une valeur obsolète s'il est appelé plusieurs fois de suite.

jsx
// Initialisation paresseuse « s'exécute une seule fois
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3

// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)

Syntaxe de useState : déclaration et mise à jour

La syntaxe de base de useState est extrêmement concise : const [state, setState] = useState(initialValue). La valeur initiale n'est utilisée que lors du premier rendu ; lors des rendus suivants, React l'ignore et retourne la valeur actuelle sauvegardée. Si le calcul initial nécessite des opérations coûteuses, passez une fonction d'initialisation : useState(() => computeExpensiveInitial()).

L'initialisation paresseuse est particulièrement importante lorsque la valeur initiale provient de localStorage, d'une transformation de données complexe ou de l'analyse de paramètres d'URL. React appelle la fonction d'initialisation une seule fois « lors du montage du composant, ce qui économise les ressources lors des rendus suivants. Sans initialisation paresseuse, l'expression coûteuse serait évaluée à chaque rendu, même si son résultat est ignoré.

FormeExempleQuand l'utiliser
DirecteuseState(0)Valeur initiale simple
ParesseuseuseState(() => compute())Calcul initial coûteux
Setter fonctionnelsetState(prev => prev + 1)Mise à jour basée sur la précédente
Setter directsetState(newValue)La nouvelle valeur ne dépend pas de l'ancienne
jsx
// État d'objet « créer une nouvelle référence
const [user, setUser] = useState(() => {
    const saved = localStorage.getItem('user');
    return saved ? JSON.parse(saved) : null;
});

useState avec différents types de données

useState fonctionne aussi bien avec les primitifs (nombres, chaînes, booléens) qu'avec les types de référence (tableaux, objets). Cependant, il y a une différence importante : pour les primitifs, React détecte les changements par valeur ; pour les objets et les tableaux, par référence. Muter un objet existant sans en créer un nouveau ne déclenchera pas de nouveau rendu car la référence reste la même.

Lorsque vous travaillez avec des objets et des tableaux, créez toujours une nouvelle copie avec les données modifiées. Pour les objets, utilisez la syntaxe de propagation : setUser(prev => ({...prev, name: newName})). Pour les tableaux, utilisez des méthodes qui retournent un nouveau tableau : filter, map, concat, ou la syntaxe de propagation pour ajouter des éléments. Les méthodes de mutation comme push, pop, splice ne fonctionneront pas « React les ignorera car la référence du tableau n'a pas changé.

jsx
// ✅ Correct : hooks au niveau supérieur
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
    setForm(prev => ({ ...prev, [field]: value }));

// ...
const [items, setItems] = useState([]);
const addItem = item =>
    setItems(prev => [item, ...prev]);

Règles d'utilisation des Hooks avec useState

Comme tous les Hooks React, useState suit deux règles. Premièrement : appelez les Hooks uniquement au niveau supérieur de votre composant « ne les placez pas à l'intérieur de conditions, de boucles ou de fonctions imbriquées. Cela garantit que les Hooks sont appelés dans le même ordre à chaque rendu, ce qui est crucial pour la liste chaînée interne de React.

Deuxièmement : appelez les Hooks uniquement depuis des composants fonctionnels React ou des Hooks personnalisés. N'appelez pas useState depuis des fonctions ordinaires, des callbacks ou des composants de classe. La violation de ces règles entraîne l'erreur Invalid hook call, que React détecte au moment de l'exécution.

  • Pas dans les conditions « if (flag) { useState(0) } viole l'ordre des appels de Hooks.
  • Pas dans les boucles « for (...) { useState(0) } rend l'ordre imprévisible.
  • Pas dans les callbacks « useEffect(() => { useState(0) }, []) casse la liste chaînée.
jsx
// ❌ Problème de fermeture obsolète
function GoodComponent() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('');
    // ✅ Corrigé avec une mise à jour fonctionnelle
}

// count est obsolète !
function BadComponent() {
    if (isLogged) {
        const [user, setUser] = useState(null);
    }
}

Erreurs courantes avec useState

L'erreur la plus courante est la mutation directe des objets et des tableaux au lieu de créer de nouvelles références. Les développeurs sont habitués au style mutable des composants de classe, où this.state.user.name = ‘Nouveau Nom’ fonctionnait (bien que cela ne soit pas non plus recommandé). Dans les composants fonctionnels, une telle mutation est simplement ignorée : React ne voit pas de changement de référence et ne refait pas le rendu du composant.

  • Mutation d'objet « user.name = ‘Nouveau’ au lieu de setUser({...user, name: ‘Nouveau’}).
  • Fermeture obsolète « utilisation d'une valeur périmée dans le setter sans la forme fonctionnelle.
  • Nouveaux rendus superflus « appel du setter avec la même valeur (React 18 effectue quand même un rendu pour les primitifs).
  • Réinitialisation d'état « mise à jour involontaire de la prop key d'un composant, provoquant son remontage.

Le problème de fermeture obsolète se produit lorsqu'un callback passé à useEffect ou à un gestionnaire d'événement capture une valeur d'état périmée de la fermeture au moment de la création du callback. La solution consiste à utiliser la forme fonctionnelle du setter ou à inclure les valeurs nécessaires dans le tableau de dépendances de useEffect. Selon la Documentation React « FAQ sur les Hooks (2025), les fermetures obsolètes sont la deuxième cause la plus fréquente de bogues dans les Hooks après les tableaux de dépendances incorrects.

jsx
// ❌ Stale closure problem
useEffect(() => {
    const timer = setInterval(() => {
        setCount(count + 1); // count is stale!
    }, 1000);
    return () => clearInterval(timer);
}, []);

// ✅ Fixed with functional update
useEffect(() => {
    const timer = setInterval(() => {
        setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(timer);
}, []);

Foire aux questions

Peut-on utiliser useState pour des objets imbriqués complexes ?

Oui, mais avec une certaine prudence. Pour les objets profondément imbriqués, chaque niveau nécessite une copie lors de la mise à jour : setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})). Si vous avez des objets avec trois niveaux d'imbrication ou plus, envisagez Immer (une bibliothèque pour les mises à jour immuables) ou divisez l'état en plusieurs appels useState pour différents niveaux.

useState est-il asynchrone ou synchrone ?

useState est asynchrone dans le sens où l'appel du setter ne met pas à jour la valeur immédiatement. React place la mise à jour dans une file d'attente et l'exécute lors du rendu suivant. Après setCount(newValue), la variable count dans la fonction actuelle contient toujours l'ancienne valeur. La nouvelle valeur ne sera disponible que lors du prochain appel du composant. Le mécanisme de regroupement garantit que les appels multiples sont regroupés en un seul rendu.

Que se passe-t-il si useState est appelé en dehors d'un composant ?

React lancera une erreur Invalid hook call. Les Hooks ne peuvent être appelés qu'à l'intérieur de composants fonctionnels React ou de Hooks personnalisés (fonctions dont le nom commence par use). Cette limitation est intégrée dans l'implémentation des Hooks : ils utilisent l'arbre fiber du composant pour stocker l'état, et en dehors d'un composant, cet arbre n'est pas disponible.

Quand utiliser useState et quand utiliser useReducer ?

useState est adapté aux états indépendants simples (compteurs, champs de saisie, indicateurs). useReducer est préférable lorsque l'état est un objet complexe avec plusieurs champs, que la logique de mise à jour dépend du type d'action ou que l'état suivant nécessite une transformation complexe. Une règle pratique : si vous avez plus de trois champs d'état interdépendants, utilisez useReducer.

Pourquoi useState ne met-il pas à jour la valeur immédiatement ?

C'est fait pour des raisons de performances. Si useState mettait à jour l'état de manière synchrone, chaque appel au setter déclencherait un nouveau rendu immédiat, entraînant de multiples redessins au sein d'un seul gestionnaire d'événement. Le regroupement par lots, où React regroupe les mises à jour et effectue un seul nouveau rendu, est une optimisation introduite dans React 16 et considérablement améliorée dans React 18 avec le regroupement automatique.

Résumé

  • useState « un Hook React de base pour gérer l'état local dans les composants fonctionnels, retournant [state, setter].
  • Immutabilité « l'état ne peut pas être muté directement ; passez toujours une nouvelle valeur ou utilisez la forme fonctionnelle du setter.
  • Initialisation paresseuse « pour les calculs initiaux coûteux, passez une fonction : useState(() => compute()).
  • Setter fonctionnel « setState(prev => prev + 1) garantit la correction avec les mises à jour groupées.
  • Regroupement par lots « React regroupe plusieurs appels au setter en un seul nouveau rendu pour l'optimisation.
  • Règles des Hooks « appelez useState uniquement au niveau supérieur du composant, pas dans les conditions ou les boucles.
  • Types de données « pour les objets et les tableaux, créez toujours une nouvelle référence lors de la mise à jour.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi