
`useRef` - Accès aux éléments DOM et valeurs persistantes
Maîtrisez le hook useRef de React pour accéder aux noeuds DOM de manière impérative et pour stocker des valeurs mutables persistantes qui ne déclenchent pas de re-renders.
Introduction : Au-delà du state et des props
Jusqu'à présent, nous avons principalement interagi avec React via le state (`useState`, `useReducer`) et les props. Ces mécanismes déclenchent des re-rendus lorsque leurs valeurs changent, permettant à l'interface utilisateur de se mettre à jour de manière déclarative. Cependant, il existe des situations où nous avons besoin d'interagir avec le DOM directement (de manière impérative) ou de conserver une valeur mutable entre les rendus sans pour autant déclencher une nouvelle mise à jour de l'UI.
C'est là qu'intervient le hook `useRef`. Il offre une échappatoire au cycle de rendu déclaratif de React pour ces cas d'usage spécifiques. `useRef` retourne un objet "ref" mutable dont la propriété .current peut être initialisée avec une valeur et modifiée sans provoquer de re-rendu. Il sert principalement à deux choses :
- Accéder directement aux noeuds du DOM.
- Conserver des valeurs mutables qui persistent pendant toute la durée de vie du composant, indépendamment des re-rendus.
Cas d'usage 1 : Accéder aux éléments du DOM
Bien que React gère le DOM pour nous, certaines tâches nécessitent un accès direct à un noeud DOM spécifique :
- Gérer le focus, la sélection de texte ou la lecture de médias.
- Déclencher des animations impératives.
- Mesurer la taille ou la position d'un élément DOM (layout).
- Intégrer des bibliothèques JavaScript tierces qui fonctionnent directement sur le DOM.
Pour cela, `useRef` permet de créer une référence qui peut être attachée à un élément React via l'attribut spécial ref.
Syntaxe :
- Créez la ref dans votre composant :
const monElementRef = useRef(null);(l'initialisation à `null` est courante pour les refs DOM). - Attachez-la à l'élément JSX désiré :
.... - Accédez au noeud DOM via
monElementRef.currentaprès que le composant a été monté et rendu.
Important : La propriété .current de la ref est assignée avec le noeud DOM correspondant après le rendu initial. Elle sera null pendant la phase de rendu initiale. Par conséquent, tout code qui accède à maRef.current doit généralement se trouver à l'intérieur d'un useEffect (qui s'exécute après le rendu) ou dans des gestionnaires d'événements.
Exemple : Mettre le focus sur un input au montage
import React, { useRef, useEffect } from 'react';
function AutoFocusInput() {
// 1. Créer la ref
const inputRef = useRef(null);
// 3. Accéder à .current après le montage
useEffect(() => {
// inputRef.current contient maintenant l'élément DOM
if (inputRef.current) {
inputRef.current.focus();
console.log('Focus mis sur l\'input !');
}
}, []); // Tableau vide pour exécuter uniquement au montage
return (
{/* 2. Attacher la ref à l'élément DOM */}
);
}
export default AutoFocusInput;
Cas d'usage 2 : Stocker des valeurs mutables persistantes
L'autre utilité majeure de `useRef` est de pouvoir conserver une valeur qui :
- Persiste entre les différents rendus du composant (comme `useState`).
- Peut être mutée directement (en modifiant `maRef.current = nouvelleValeur`).
- Ne déclenche PAS de re-rendu lorsque sa propriété `.current` est modifiée.
Ceci contraste fondamentalement avec `useState`, où l'appel de la fonction `setState` déclenche un re-rendu. `useRef` est donc utile lorsque vous avez besoin de suivre une information pendant la durée de vie du composant, mais que cette information n'a pas d'impact direct sur le rendu visuel.
Exemples typiques :
- Stocker l'ID retourné par `setTimeout` ou `setInterval` pour pouvoir l'annuler plus tard dans une fonction de nettoyage `useEffect`.
- Garder une référence à la valeur précédente d'une prop ou d'un état.
- Implémenter un compteur de rendus (bien que principalement pour le débogage).
- Stocker toute autre valeur mutable dont le changement ne doit pas affecter l'UI.
Exemple : Stocker un ID de Timer
import React, { useState, useRef, useEffect } from 'react';
function StoppableTimer() {
const [seconds, setSeconds] = useState(0);
// Ref pour stocker l'ID de l'intervalle
const intervalRef = useRef(null);
const startTimer = () => {
// Ne démarre pas si déjà démarré
if (intervalRef.current !== null) return;
console.log('Démarrage du timer...');
intervalRef.current = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
};
const stopTimer = () => {
if (intervalRef.current === null) return;
console.log('Arrêt du timer...');
clearInterval(intervalRef.current);
intervalRef.current = null; // Réinitialise la ref
};
// Nettoyage au démontage
useEffect(() => {
// Retourne la fonction de nettoyage qui utilise la ref
return () => {
if (intervalRef.current) {
console.log('Nettoyage du timer au démontage...');
clearInterval(intervalRef.current);
}
};
}, []);
return (
Secondes : {seconds}
);
}
export default StoppableTimer;
Ici, `intervalRef.current` est modifié directement pour stocker et lire l'ID du timer. Changer `intervalRef.current` ne cause pas de re-rendu, ce qui est exactement le comportement souhaité.
`useRef` vs `useState` : Récapitulatif
| Caractéristique | `useRef` | `useState` |
|---|---|---|
| Objet Retourné | Objet ref ({ current: ... }) | Tableau ([valeur, setValeur]) |
| Persistance | Oui, pendant toute la vie du composant | Oui, pendant toute la vie du composant |
| Déclenche un re-rendu lors du changement ? | Non | Oui (via `setValeur`) |
| Comment mettre à jour ? | Mutation directe (maRef.current = ...) | Fonction de mise à jour (setValeur(...)) |
| Cas d'usage principal | Accès DOM, valeurs mutables sans re-rendu | Etat dont les changements doivent mettre à jour l'UI |
Conclusion : Un outil pour l'impératif et la persistance discrète
Le hook `useRef` est un outil essentiel dans la boîte à outils React, mais il est destiné à des cas d'usage spécifiques qui sortent du flux déclaratif habituel. Il fournit une "trappe de secours" pour interagir directement avec le DOM lorsque c'est nécessaire et un moyen de conserver des informations mutables entre les rendus sans déclencher le coûteux processus de mise à jour de l'interface.
Comprendre quand utiliser `useRef` (pour l'accès DOM ou les valeurs persistantes non liées au rendu) par opposition à `useState` (pour l'état qui pilote l'UI) est fondamental pour écrire des composants React efficaces et corrects.