React Hooks — ce qu’ils sont, hooks principaux et règles d’utilisation

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

React Hooks sont des fonctions qui permettent d’utiliser l’état, les effets, le contexte et d’autres fonctionnalités de React dans des composants fonctionnels, sans écrire de classes. Introduits dans React 16.8, les hooks ont radicalement changé l’approche de développement, remplaçant des motifs complexes comme HOC et render props. Selon React, 2024, il existe 15 hooks intégrés couvrant tous les scénarios de gestion de composants.

À retenir

  • Hooks — fonctions pour connecter les fonctionnalités de React aux composants fonctionnels sans extends Component.
  • useState — le hook de base pour la gestion d’état, retourne une valeur et un setter.
  • useEffect — pour les effets de bord : requêtes API, abonnements, minuteurs, manipulations DOM.
  • useContext — pour accéder au contexte React sans wrappers Consumer ni static contextType.
  • Règles des hooks — appeler uniquement au niveau supérieur et uniquement dans les composants fonctionnels ou les hooks personnalisés.

Que sont les React Hooks ?

React Hooks sont un ensemble de fonctions intégrées à React qui permettent de « se brancher » sur les mécanismes internes du framework sans créer de classes. Avant React 16.8, les composants fonctionnels pouvaient seulement accepter des props et retourner du JSX — toute logique complexe nécessitait un composant de classe.

Le problème des composants de classe est la division de la logique connexe. Le code lié à une même entité (par exemple, un abonnement WebSocket) était forcément divisé entre componentDidMount, componentDidUpdate et componentWillUnmount. Les hooks résolvent cela : toute la logique est groupée dans un seul useEffect.

Le deuxième problème est la réutilisation de la logique. Pour réutiliser la logique d’état entre composants de classe, il fallait appliquer des HOC (Composants d’Ordre Supérieur) ou render props — les deux motifs créaient un imbrication supplémentaire dans l’arbre de composants. Les hooks personnalisés résolvent cela sans imbrication.

useState — Gestion d’état

useState est le hook le plus basique. Il prend une valeur initiale et retourne un tuple : la valeur actuelle et une fonction pour la mettre à jour. Contrairement à this.setState dans les classes, useState ne fusionne pas les objets — le nouvel état remplace complètement le précédent pour un appel useState spécifique.

js
import React, { useState } from 'react';

function Form() {
  const [text, setText] = useState('');
  const [submitting, setSubmitting] = useState(false);

  async function handleSubmit() {
    setSubmitting(true);
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify({ text })
    });
    setSubmitting(false);
  }

  return (
    <div>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={handleSubmit}
        disabled={submitting}>
        {submitting ? 'Saving...' : 'Submit'}
      </button>
    </div>
  );
}

Forme fonctionnelle de setState

Le setter de useState peut accepter une fonction qui reçoit la valeur précédente et en retourne une nouvelle. La forme fonctionnelle est obligatoire lorsque le nouvel état est calculé à partir du précédent et que des appels setState groupés sont possibles — chaque appel recevra la valeur précédente actuelle.

useEffect — Effets de bord et cycle de vie

useEffect est un hook pour effectuer des effets de bord dans les composants fonctionnels. Il prend deux arguments : une fonction d’effet et un tableau de dépendances. React exécute l’effet après chaque rendu, mais lorsque des dépendances sont spécifiées — seulement lorsque l’une d’elles change.

Un tableau de dépendances vide [] signifie que l’effet s’exécute une fois après le premier rendu (analogue à componentDidMount). Retourner une fonction depuis l’effet est un nettoyage qui s’exécute au démontage (analogue à componentWillUnmount) et avant la réexécution de l’effet.

js
import React, { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket(`wss://chat/${roomId}`);

    socket.onmessage = (event) => {
      setMessages(prev => [...prev, JSON.parse(event.data)]);
    };

    // Nettoyage - fermer le socket
    return () => socket.close();
  }, [roomId]);

  return <ul>
    {messages.map((msg, i) =>
      <li key={i}>{msg.text}</li>
    )}
  </ul>;
}

Les dépendances de useEffect sont la seule connexion entre l’effet et le monde extérieur. Si l’effet utilise une variable des props ou de l’état, elle doit figurer dans le tableau de dépendances. Ignorer cette règle est une source de bogues avec des fermetures périmées (stale closures).

useContext — Accès au contexte

useContext est un hook pour lire les valeurs du contexte. Il prend un objet contexte créé par React.createContext et retourne la valeur actuelle. Si le contexte change, le composant se re-rend automatiquement avec la nouvelle valeur.

Avant useContext, accéder au contexte dans les composants fonctionnels nécessitait un enveloppement dans Context.Consumer, ce qui créait de l’imbrication. useContext élimine complètement Consumer — il suffit d’appeler le hook n’importe où dans le composant fonctionnel.

js
import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('clair');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button
    className={`btn btn-${theme}`}
  >
    {theme === 'dark' ? 'moon' : '☀️'}
  </button>;
}

useContext n’est pas un remplacement de Redux ou de l’état global. React recommande d’utiliser le contexte pour des valeurs qui changent rarement — thème, locale, statut d’authentification. Pour des données fréquemment mises à jour, chaque re-rendu recalcule tous les consommateurs du contexte, ce qui peut réduire les performances.

useReducer — Logique d’état complexe

useReducer est une alternative à useState pour les états avec une logique de mise à jour complexe. Il prend une fonction réductrice et un état initial, retourne l’état actuel et une fonction dispatch. Le réducteur reçoit l’état actuel et une action, retourne un nouvel état — une fonction pure sans effets de bord.

useReducer est particulièrement utile lorsque plusieurs actions (set, reset, increment, addItem) gèrent un même état. Au lieu de plusieurs useState avec différents setters — un seul réducteur avec des types d’action clairs. Cela rend la logique prévisible et facile à tester.

js
import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'setStep':
      return { ...state, step: action.step };
    case 'reset':
      return { count: 0, step: 1 };
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, {
    count: 0,
    step: 1
  });

  return (
    <>
      <p>Count: {state.count}</p>
      <button
        onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button
        onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </>
  );
}

useRef, useMemo, useCallback — Optimisation

useRef crée un objet mutable qui persiste entre les rendus. Modifier current ne déclenche pas un re-rendu. Les principales utilisations sont l’accès aux éléments DOM et le stockage de valeurs mutables (minuteurs, valeurs précédentes, instances de bibliothèques).

useMemo mémorise le résultat d’une fonction. Il ne recalcule la valeur que lorsqu’une dépendance change. Utilisez-le pour des calculs coûteux — filtrage de grands tableaux, tri, formatage de données. useCallback est un cas particulier de useMemo pour mémoriser des fonctions.

js
import React, { useRef, useMemo, useCallback } from 'react';

function SearchPage({ items, query, onItemSelect }) {
  const inputRef = useRef(null);

  // Autofocus au montage
  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  // Mémoriser le résultat filtré
  const filtered = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase()
        .includes(query.toLowerCase())
    );
  }, [items, query]);

  // Mémoriser le callback
  const handleSelect = useCallback((id) => {
    onItemSelect(id);
  }, [onItemSelect]);

  return (
    <div>
      <input ref={inputRef}
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <ul>
        {filtered.map(item =>
          <li key={item.id}>
            <button
              onClick={() => handleSelect(item.id)}>
              {item.name}
            </button>
          </li>
        )}
      </ul>
    </div>
  );
}

Une règle importante : useRef, useMemo et useCallback sont des outils d’optimisation, pas des constructions obligatoires. N’enveloppez pas tout dans useMemo — mesurez d’abord les performances. L’optimisation prématurée complique le code. React rend les composants rapidement ; useMemo n’est nécessaire que lorsque les calculs sont vraiment coûteux (O(n²) et plus).

Règles des hooks et erreurs courantes

React a introduit deux règles strictes pour les hooks. Première : appelez les hooks uniquement au niveau supérieur — pas à l’intérieur de conditions, boucles ou fonctions imbriquées. Deuxième : appelez les hooks uniquement à partir de composants fonctionnels React ou de hooks personnalisés. Le plugin ESLint eslint-plugin-react-hooks vérifie automatiquement les deux règles.

L’erreur la plus courante est la violation de l’ordre d’appel des hooks. React repose sur l’ordre d’appel des hooks entre les rendus. Si un hook se trouve à l’intérieur d’une condition et ne s’exécute pas lors d’un rendu, tous les hooks suivants se décalent, provoquant des bogues.

ErreurCe qui se passeSolution
Hook dans une conditionL’ordre des hooks est briséDéplacez la logique conditionnelle à l’intérieur du hook
Stale closureL’effet utilise une valeur ancienneAjoutez toutes les dépendances au tableau
Boucle infinieuseEffect sans dépendances modifie l’étatSpécifiez les dépendances ou utilisez useReducer
Mutation de ref dans le renduEffet de bord dans le corps de la fonctionDéplacez les mutations dans useEffect

La deuxième erreur courante est la stale closure dans useEffect. Si l’effet utilise une variable non spécifiée dans les dépendances, l’effet «capture» sa valeur au moment de la création de la fermeture. La solution est de toujours inclure toutes les variables utilisées dans le tableau de dépendances. S’il y a trop de dépendances, envisagez de diviser l’effet en plusieurs.

Foire aux questions

Pourquoi les hooks ne peuvent-ils pas être appelés dans des conditions ?

React repose sur l’ordre d’appel des hooks entre les rendus. Si un hook est appelé à l’intérieur d’une condition et ne se déclenche pas lors d’un rendu, tous les hooks suivants se décalent — leur état se mélange. La règle ESLint hooks/exhaustive-deps avertit de cela.

Quelle est la différence entre useEffect et useLayoutEffect ?

useLayoutEffect est synchrone et s’exécute avant que le navigateur n’affiche les modifications. useEffect est asynchrone — après l’affichage. Utilisez useLayoutEffect uniquement lorsque vous devez mesurer ou modifier le DOM avant que l’utilisateur ne voie les changements (position d’une popover, restauration du défilement).

Comment annuler une requête fetch au démontage ?

Utilisez AbortController à l’intérieur de useEffect. Créez un controller, passez le signal à fetch, et appelez controller.abort() dans la fonction de nettoyage. Pour les navigateurs plus anciens, utilisez un indicateur cancelled : return () => { cancelled = true; } avec une vérification avant setState.

Qu’est-ce qu’un hook personnalisé et quand en créer un ?

Un hook personnalisé est une fonction JavaScript avec le préfixe use qui utilise des hooks intégrés. Créez-en un lorsque la même logique avec des hooks se répète dans deux composants ou plus. Exemples : useDebounce, useLocalStorage, useMediaQuery. Les hooks personnalisés remplacent les HOC et render props.

Pourquoi useEffect s’exécute-t-il deux fois en Strict Mode ?

En Strict Mode, React monte et démonte intentionnellement le composant deux fois en développement pour trouver des bogues avec des effets non nettoyés. Si le nettoyage est écrit correctement, le double appel ne pose aucun problème. Cela ne se produit pas en mode production.

Résumé

  • React Hooks — fonctions pour utiliser l’état, les effets et le contexte dans les composants fonctionnels, remplaçant les classes.
  • useState — hook de base pour l’état local avec un setter fonctionnel pour des mises à jour sûres.
  • useEffect — hook universel pour les effets de bord avec tableau de dépendances et fonction de nettoyage.
  • useContext — accès direct au contexte React sans wrappers Consumer ni imbrication supplémentaire.
  • useReducer — pour la logique d’état complexe avec des types d’action, une alternative à Redux au sein d’un seul composant.
  • useRef, useMemo, useCallback — outils d’optimisation : références DOM, mémorisation de valeurs et de callbacks.
  • Règle du niveau supérieur — restriction stricte d’appeler les hooks en dehors des conditions, boucles et fonctions imbriquées.

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