Kodokon kodokon.com

useRef et manipulation du DOM

Manipulez le DOM et conservez des valeurs d'instance avec useRef, sans casser la pureté du rendu.

7 min · 3 questions

Ouvrir cette leçon dans Kodokon

useRef retourne une boîte mutable - un objet doté d'une seule propriété current - dont l'identité survit à tous les rendus. Deux différences fondamentales avec l'état : modifier ref.current ne déclenche aucun re-rendu, et la modification est visible immédiatement, sans attendre le rendu suivant. Deux familles d'usage en découlent : référencer un nœud du DOM, et stocker une valeur d'instance qui doit survivre aux rendus sans piloter l'affichage.

JSX
import { useEffect, useRef } from "react";

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

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} type="search" />;
}
React attache le nœud à la ref après le commit du rendu.

Côté valeur d'instance, tout ce qui doit persister sans provoquer d'affichage a sa place dans une ref : l'identifiant retourné par setInterval, l'instance d'une bibliothèque externe (carte, éditeur, lecteur vidéo), ou la valeur d'un rendu précédent. La règle d'or reste la même : le rendu doit être une fonction pure des props et de l'état. Les refs se lisent et s'écrivent dans les effets et les gestionnaires d'événements, pas pendant le rendu.

JAVASCRIPT
import { useEffect, useRef } from "react";

function usePrevious(value) {
  const ref = useRef(undefined);

  useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}
L'effet court après le rendu : la ref garde un rendu de retard.

Pour exposer un nœud DOM depuis votre propre composant, transmettez la ref : depuis React 19, ref est une prop ordinaire des composants fonction ; auparavant, un passage par forwardRef était obligatoire. Dernier réflexe à cultiver : préférez le déclaratif quand un état suffit à décrire le résultat (classe CSS, attribut disabled). Réservez les refs aux territoires que React ne couvre pas : focus, sélection de texte, mesure d'un élément, défilement, lecture de médias.

JSX
import { useRef } from "react";

function TextField({ ref, ...props }) {
  return <input ref={ref} {...props} />;
}

function Form() {
  const fieldRef = useRef(null);

  return (
    <>
      <TextField ref={fieldRef} />
      <button onClick={() => fieldRef.current.focus()}>
        Donner le focus
      </button>
    </>
  );
}
Depuis React 19, ref se transmet comme n'importe quelle prop.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Quelle différence fondamentale sépare useRef de useState pour stocker une valeur ?
    • Modifier ref.current ne déclenche aucun re-rendu, contrairement à une mise à jour d'état
    • useRef conserve sa valeur après le démontage du composant
    • useRef ne peut stocker que des nœuds du DOM
    • Les refs sont partagées entre toutes les instances d'un composant
  2. Pourquoi accéder à inputRef.current dans useEffect plutôt que pendant le rendu ?
    • Parce que useEffect regroupe les accès au DOM pour de meilleures performances
    • Parce que les refs sont verrouillées en lecture pendant le rendu
    • Parce que React n'attache le nœud qu'après le commit : pendant le premier rendu, current vaut encore null
  3. Que retourne usePrevious(value) lors du tout premier rendu ?
    • La valeur courante de value
    • undefined, car l'effet qui écrit dans la ref ne s'est pas encore exécuté
    • null
    • La valeur du rendu suivant