Améliorez l’ergonomie de votre poste de développeur en 2026

Optimisez vos composants React, simplifiez votre code et améliorez les performances de vos applications web.

En 2026, les Hooks React sont devenus une pierre angulaire du développement moderne, offrant une approche plus fonctionnelle et réutilisable pour gérer l’état et le cycle de vie des composants. Ce guide pratique vous accompagnera pas à pas pour maîtriser ces outils essentiels, de leurs principes fondamentaux à leurs applications les plus avancées, afin de construire des interfaces utilisateur robustes et efficaces.

06Bonnes Pratiques et Pièges à Éviter avec les Hooks

07Conclusion : Exploiter la Puissance des Hooks React pour des Applications Modernes

Introduction : Maîtriser les Hooks React en 2026

Introduction : Maîtriser les Hooks React en 2026

Depuis leur introduction en 2019, les Hooks ont révolutionné la manière dont les développeurs abordent la logique d’état et de cycle de vie dans les composants fonctionnels React. En 2026, ils sont devenus le standard de facto, remplaçant les composants de classe dans la plupart des nouveaux projets et refactorings. Cette transition a apporté une clarté et une flexibilité considérables, permettant de créer des applications plus maintenables et performantes.

L’objectif de ce guide est de vous fournir une compréhension approfondie et des compétences pratiques pour utiliser efficacement les Hooks React. Que vous soyez un développeur expérimenté cherchant à consolider vos connaissances ou un débutant souhaitant démarrer avec les bonnes pratiques, vous trouverez ici les informations nécessaires pour exceller.

La maîtrise des Hooks React est indispensable pour tout développeur React moderne, permettant de construire des applications plus robustes et performantes.

Nous explorerons les Hooks fondamentaux comme useState et useEffect, puis nous plongerons dans les Hooks d’optimisation tels que useMemo et useCallback. Enfin, nous aborderons les Hooks plus avancés et la création de Hooks personnalisés, un aspect crucial pour la réutilisabilité du code.

Les Fondamentaux des Hooks React : Pourquoi et Comment

Les Fondamentaux des Hooks React : Pourquoi et Comment

Avant les Hooks, la gestion de l’état et des effets secondaires dans React se faisait principalement via des composants de classe. Ceux-ci présentaient des inconvénients notables, notamment la complexité liée à this, la difficulté à réutiliser la logique d’état entre les composants (patterns comme Render Props ou Higher-Order Components pouvaient devenir verbeux), et la fragmentation de la logique liée à une même fonctionnalité (par exemple, le code de récupération de données dispersé entre componentDidMount et componentDidUpdate).

Les Hooks ont été introduits pour résoudre ces problèmes. Ils permettent d’utiliser l’état et d’autres fonctionnalités de React sans écrire de classe. Ils encouragent une approche plus fonctionnelle et déclarative, rendant le code plus lisible et réutilisable.


Qu’est-ce qu’un Hook ?

Un Hook est une fonction JavaScript spéciale qui vous permet de « brancher » des fonctionnalités React (comme l’état ou le cycle de vie) dans des composants fonctionnels. Tous les Hooks commencent par le préfixe use (par exemple, useState, useEffect), ce qui est une convention essentielle pour que React puisse les détecter et les gérer correctement.

Les Règles des Hooks

Il existe deux règles fondamentales à respecter impérativement lors de l’utilisation des Hooks :

1. N’appelez les Hooks qu’au niveau le plus élevé (top level) de votre composant fonctionnel. Ne les appelez pas à l’intérieur de boucles, de conditions 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 que React puisse maintenir l’état interne des Hooks correctement. C’est une erreur très courante pour les débutants.

2. N’appelez les Hooks qu’à partir de fonctions React. Cela inclut les composants fonctionnels React et les Hooks personnalisés. Ne les appelez pas à partir de fonctions JavaScript ordinaires. Cette règle assure que les Hooks sont utilisés dans le contexte d’un composant React, où leur état et leur cycle de vie peuvent être gérés par le framework.

Le respect de ces règles est vital pour éviter des bugs difficiles à diagnostiquer et pour garantir le bon fonctionnement de vos applications React.

Hooks d’État et d’Effet : useState et useEffect en Profondeur

Hooks d'État et d'Effet : useState et useEffect en Profondeur

Les Hooks useState et useEffect sont les piliers des Hooks React. Ils vous permettent de gérer l’état local d’un composant et d’exécuter des effets secondaires, respectivement.

Comprendre comment useState et useEffect fonctionnent ensemble est la clé pour construire des composants React interactifs et dynamiques.

useState : Gérer l’état local

useState est le Hook fondamental pour ajouter l’état à un composant fonctionnel. Il retourne une paire de valeurs : l’état actuel et une fonction pour le mettre à jour. Vous pouvez l’appeler plusieurs fois dans un même composant pour gérer différents morceaux d’état.

Syntaxe : const [state, setState] = useState(initialState);

  • state : La valeur actuelle de l’état.
  • setState : Une fonction qui vous permet de mettre à jour state. Lorsque vous appelez cette fonction, React re-rend le composant avec la nouvelle valeur.
  • initialState : La valeur initiale de l’état. Elle peut être une valeur primitive (nombre, chaîne, booléen) ou un objet/tableau. Si initialState est une fonction, elle sera exécutée une seule fois lors du rendu initial pour calculer l’état initial.

Exemple pratique de useState :

Explication du code:

Ce composant simple gère un compteur. Chaque clic sur le bouton incrémente le compteur.
import React, { useState } from 'react';

function Compteur() {
  const [nombre, setNombre] = useState(0); // Initialise l'état 'nombre' à 0

  const incrementer = () => {
    setNombre(nombre + 1); // Met à jour l'état 'nombre'
  };

  return (
    <div>
      <p>Compteur : {nombre}</p>
      <button onClick={incrementer}>Incrémenter</button>
    </div>
  );
}

export default Compteur;

useEffect : Gérer les effets secondaires

useEffect vous permet d’effectuer des effets secondaires dans les composants fonctionnels. Les effets secondaires sont des opérations qui interagissent avec le monde extérieur à React, comme la récupération de données, la manipulation directe du DOM, les abonnements, les timers, etc. Il remplace les méthodes de cycle de vie comme componentDidMount, componentDidUpdate et componentWillUnmount.

Syntaxe : useEffect(() => { / effet / return () => { / nettoyage / }; }, [dépendances]);

  • Fonction d’effet : La première fonction passée à useEffect est l’effet lui-même. Elle sera exécutée après chaque rendu où les dépendances ont changé.
  • Fonction de nettoyage (optionnel) : Si votre effet retourne une fonction, celle-ci sera exécutée lorsque le composant sera démonté ou avant que l’effet ne soit ré-exécuté. C’est essentiel pour désabonner des services ou nettoyer des ressources afin d’éviter les fuites de mémoire.
  • Tableau de dépendances (optionnel) : Le deuxième argument est un tableau de valeurs dont l’effet dépend.
    • Si le tableau est vide ([]), l’effet s’exécute une seule fois après le premier rendu (équivalent à componentDidMount).
    • Si le tableau est omis, l’effet s’exécute après chaque rendu (équivalent à componentDidMount + componentDidUpdate).
    • Si le tableau contient des valeurs, l’effet s’exécute après le premier rendu et après chaque rendu où l’une des valeurs du tableau a changé.

Exemple de useEffect (récupération de données) :

Explication du code:

Ce composant récupère des données d'API lorsqu'il est monté et met à jour l'état. Il gère également le chargement et les erreurs.
import React, { useState, useEffect } from 'react';

function DataLoader({ userId }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      setError(null);
      try {
        const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
        if (!response.ok) {
          throw new Error(`Erreur HTTP: ${response.status}`);
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [userId]); // L'effet se ré-exécute si 'userId' change

  if (loading) return <p>Chargement des données...</p>;
  if (error) return <p style="color: red;">Erreur : {error.message}</p>;
  if (!data) return <p>Aucune donnée trouvée.</p>;

  return (
    <div>
      <h3>Détails de l'utilisateur {userId}</h3>
      <p>Nom : {data.name}</p>
      <p>Email : {data.email}</p>
    </div>
  );
}

export default DataLoader;

Dans cet exemple, l’effet s’exécute lorsque le composant est monté et à chaque fois que la prop userId change. Si userId ne change jamais, l’effet ne s’exécute qu’une seule fois.

Hooks de Performance : useMemo, useCallback et useRef

Hooks de Performance : useMemo, useCallback et useRef

Au-delà de la gestion de l’état et des effets, React offre des Hooks pour optimiser les performances de vos applications en évitant les calculs coûteux et les rendus inutiles. Ces Hooks sont particulièrement utiles dans les applications de grande envergure ou avec des composants qui se re-rendent fréquemment.

L’utilisation judicieuse de useMemo, useCallback et useRef peut considérablement améliorer la réactivité de vos applications React.

useMemo : Mémoriser des valeurs coûteuses

useMemo est un Hook qui mémorise la valeur d’une fonction. Il ne re-calculera la valeur que si l’une de ses dépendances a changé. C’est utile pour optimiser les calculs coûteux qui ne dépendent que de certaines valeurs. Sans useMemo, ces calculs seraient exécutés à chaque rendu du composant, même si les entrées n’ont pas changé.

Syntaxe : const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Exemple de useMemo :

Explication du code:

Ce composant utilise useMemo pour calculer la factorielle d'un nombre, évitant des recalculs inutiles si le nombre ne change pas.
import React, { useState, useMemo } from 'react';

const calculerFactorielle = (n) => {
  console.log('Calcul de la factorielle...');
  if (n < 0) return -1;
  if (n === 0) return 1;
  let result = 1;
  for (let i = 1; i <= n; i++) {
    result *= i;
  }
  return result;
};

function ComposantAvecMemo() {
  const [nombre, setNombre] = useState(5);
  const [autreCompteur, setAutreCompteur] = useState(0);

  // La factorielle ne sera recalculée que si 'nombre' change
  const factorielle = useMemo(() => calculerFactorielle(nombre), [nombre]);

  return (
    <div>
      <h3>Calcul de Factorielle</h3>
      <input
        type="number"
        value={nombre}
        onChange={(e) => setNombre(parseInt(e.target.value))}
      />
      <p>La factorielle de {nombre} est : {factorielle}</p>

      <hr style="border: none; border-top: 1px dashed #D1D6DB; height: 0; background: transparent;">

      <h3>Autre Compteur</h3>
      <p>Compteur secondaire : {autreCompteur}</p>
      <button onClick={() => setAutreCompteur(autreCompteur + 1)}>
        Incrémenter l'autre compteur
      </button>
    </div>
  );
}

export default ComposantAvecMemo;

Remarquez que « Calcul de la factorielle… » n’apparaît dans la console que lorsque le champ « nombre » est modifié, pas lorsque « autreCompteur » est incrémenté.


useCallback : Mémoriser des fonctions

useCallback est similaire à useMemo, mais il mémorise une fonction de callback plutôt qu’une valeur. Cela est particulièrement utile lorsque vous passez des fonctions à des composants enfants optimisés avec React.memo. Sans useCallback, une nouvelle instance de la fonction serait créée à chaque rendu du parent, forçant le composant enfant à se re-rendre même si ses props n’ont pas « logiquement » changé.

Syntaxe : const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);

Exemple de useCallback :

Explication du code:

Un composant parent passe une fonction de rappel à un enfant optimisé avec React.memo. useCallback empêche l'enfant de se re-rendre inutilement.
import React, { useState, useCallback } from 'react';

// Composant enfant optimisé avec React.memo
const BoutonEnfant = React.memo(({ onClick, texte }) => {
  console.log(`Rendu de BoutonEnfant : ${texte}`);
  return <button onClick={onClick}>{texte}</button>;
});

function ComposantParent() {
  const [compteur, setCompteur] = useState(0);
  const [autreCompteur, setAutreCompteur] = useState(0);

  // La fonction handleIncrement sera mémorisée et ne changera que si 'compteur' change
  const handleIncrement = useCallback(() => {
    setCompteur((prevCompteur) => prevCompteur + 1);
  }, []); // Dépendance vide : la fonction ne change jamais

  // La fonction handleAutreIncrement sera mémorisée et ne changera que si 'autreCompteur' change
  const handleAutreIncrement = useCallback(() => {
    setAutreCompteur((prevAutreCompteur) => prevAutreCompteur + 1);
  }, []); // Dépendance vide pour cet exemple, mais pourrait dépendre de 'autreCompteur' si nécessaire

  return (
    <div>
      <h3>Composant Parent</h3>
      <p>Compteur principal : {compteur}</p>
      <BoutonEnfant onClick={handleIncrement} texte="Incrémenter principal" />

      <hr style="border: none; border-top: 1px dashed #D1D6DB; height: 0; background: transparent;">

      <p>Autre compteur : {autreCompteur}</p>
      <BoutonEnfant onClick={handleAutreIncrement} texte="Incrémenter autre" />
    </div>
  );
}

export default ComposantParent;

Si vous cliquez sur « Incrémenter principal », seul le BoutonEnfant correspondant se re-rendra, et non l’autre, grâce à useCallback et React.memo.


useRef : Accéder aux éléments DOM et valeurs mutables

useRef retourne un objet ref mutable dont la propriété .current est initialisée avec l’argument passé (initialValue). L’objet retourné persistera pendant toute la durée de vie du composant. Il est couramment utilisé pour :

  • Accéder directement à un élément DOM.
  • Stocker une valeur mutable qui ne déclenche pas de re-rendu lorsque elle est modifiée (contrairement à useState).

Syntaxe : const myRef = useRef(initialValue);

Exemple de useRef (accès au DOM) :

Explication du code:

Ce composant utilise useRef pour créer une référence à un élément input, permettant de le focaliser programmatiquement.
import React, { useRef } from 'react';

function FormulaireAvecRef() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus(); // Accède à l'élément DOM et le focalise
  };

  return (
    <div>
      <h3>Focus automatique avec useRef</h3>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focaliser l'input</button>
    </div>
  );
}

export default FormulaireAvecRef;

Hooks Avancés : useContext, useReducer et Hooks Personnalisés

Hooks Avancés : useContext, useReducer et Hooks Personnalisés

Au-delà des Hooks de base et d’optimisation, React propose des outils plus puissants pour gérer des scénarios complexes. useContext simplifie le partage d’état global, useReducer offre une alternative robuste à useState pour les états complexes, et les Hooks personnalisés sont la clé de la réutilisabilité de la logique d’état.

Les Hooks avancés et personnalisés permettent de construire des architectures React hautement modulaires et maintenables.

useContext : Partager l’état global

React Context API, combinée avec le Hook useContext, permet de partager des données (état, fonctions, thèmes, etc.) à travers l’arbre de composants sans avoir à passer les props manuellement à chaque niveau (ce qu’on appelle le « prop drilling »).

Étapes :

  • Créez un Contexte : const MonContexte = React.createContext(defaultValue);
  • Fournissez le Contexte : Enveloppez vos composants avec <MonContexte.Provider value={...}>.
  • Consommez le Contexte : Utilisez const value = useContext(MonContexte); dans le composant fonctionnel.

Exemple de useContext (thème) :

Explication du code:

Crée un contexte de thème pour partager le mode clair/sombre dans toute l'application, et un bouton pour le basculer.
import React, { useState, useContext, createContext } from 'react';

// 1. Créer le Contexte
const ThemeContext = createContext(null);

// Composant qui consomme le thème
function Contenu() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  const style = {
    background: theme === 'light' ? '#fff' : '#333',
    color: theme === 'light' ? '#333' : '#fff',
    padding: '20px',
    border: '1px solid #ccc'
  };

  return (
    <div style={style}>
      <p>Ceci est un contenu avec le thème {theme}.</p>
      <button onClick={toggleTheme}>Changer de thème</button>
    </div>
  );
}

// Composant parent qui fournit le thème
function AppTheme() {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      <h3>Application de Thème</h3>
      <Contenu />
    </ThemeContext.Provider>
  );
}

export default AppTheme;

useReducer : Gérer l’état complexe

useReducer est une alternative à useState pour la gestion d’état. Il est particulièrement utile lorsque vous avez une logique d’état complexe impliquant plusieurs sous-valeurs ou lorsque le prochain état dépend du précédent. Il est souvent préféré pour des états qui sont mis à jour par des actions bien définies, comme dans une architecture Redux.

Syntaxe : const [state, dispatch] = useReducer(reducer, initialState, init);

  • reducer : Une fonction qui prend l’état actuel et une action en arguments, et retourne le nouvel état.
  • initialState : La valeur initiale de l’état.
  • init (optionnel) : Une fonction pour calculer l’état initial de manière paresseuse.
  • dispatch : Une fonction que vous appelez avec une action pour déclencher une mise à jour de l’état.

Exemple de useReducer (gestion de tâche) :

Explication du code:

Ce composant gère une liste de tâches avec des actions d'ajout, de suppression et de basculement.
import React, { useReducer, useState } from 'react';

// Fonction reducer
function taskReducer(state, action) {
switch (action.type) {
case 'ADD_TASK':
return [
...state,
{ id: Date.now(), text: action.payload, completed: false },
];
case 'TOGGLE_TASK':
return state.map((task) =>
task.id === action.payload
? { ...task, completed: !task.completed }
: task
);
case 'REMOVE_TASK':
return state.filter((task) => task.id !== action.payload);
default:
return state;
}
}

function TaskList() {
const [tasks, dispatch] = useReducer(taskReducer, []);
const [taskText, setTaskText] = useState('');

const handleAddTask = () => {
if (taskText.trim()) {
dispatch({ type: 'ADD_TASK', payload: taskText });
setTaskText('');
}
};

return (
<div>
<h3>Liste de Tâches avec useReducer</h3>
<input
type="text"
value={taskText}
onChange={(e) => setTaskText(e.target.value)}
placeholder="Ajouter une nouvelle tâche"
/>
<button onClick={handleAddTask}>Ajouter</button>
<ul>
{tasks.map((task) => (
<li key={task.id}>
<input
type="checkbox"
checked={task.completed}
onChange={() => dispatch({ type: 'TOGGLE_TASK', payload: task.id })}
/>
<span style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
{task.text}
</span>
<button onClick={() => dispatch({ type: 'REMOVE_TASK', payload: task.id })}
style={{ marginLeft: '10px' }}>
Supprimer
</button>
</li>
))}
</ul>
</div>
);