
Typer les refs (`useRef`)
Apprenez à utiliser TypeScript pour typer correctement les refs créées avec le hook `useRef` en React, que ce soit pour accéder aux éléments DOM ou stocker des valeurs mutables.
Le double rôle de `useRef` et le besoin de typage
Le hook `useRef` en React sert principalement à deux objectifs :
- Accéder directement aux noeuds du DOM (pour gérer le focus, mesurer des éléments, intégrer des bibliothèques non-React, etc.).
- Stocker une valeur mutable qui persiste entre les rendus sans provoquer de nouveau rendu lorsque sa valeur change (contrairement à `useState`).
Dans les deux cas, l'accès à la valeur se fait via la propriété .current de l'objet ref retourné par `useRef`. En JavaScript simple, la nature de `ref.current` peut varier, et tenter d'accéder à une propriété ou méthode incorrecte peut entraîner des erreurs d'exécution.
TypeScript, grâce à son système de génériques, nous permet de spécifier le type de valeur que la propriété .current est censée contenir, rendant ainsi l'utilisation des refs beaucoup plus sûre et prévisible.
Typage des Refs pour les éléments DOM
C'est le cas d'usage le plus courant nécessitant un typage attentif. Lorsque vous créez une ref pour un élément DOM, sa valeur initiale est presque toujours `null`. La ref n'est assignée à l'élément DOM réel qu'après le premier rendu, lorsque React attache la ref à l'élément correspondant dans le JSX.
Par conséquent, le type de `ref.current` pour une ref DOM doit indiquer qu'il peut être soit le type de l'élément DOM spécifique (ex: `HTMLInputElement`, `HTMLDivElement`, `HTMLButtonElement`), soit `null`.
La syntaxe utilise le générique de `useRef` :
import React, { useRef, useEffect } from 'react';
function FocusInput() {
// 1. Typer la ref: elle peut contenir un HTMLInputElement ou null
const inputRef = useRef(null);
useEffect(() => {
// 3. Vérifier si current n'est pas null avant d'accéder à ses méthodes
if (inputRef.current) {
inputRef.current.focus();
}
}, []); // Se déclenche après le premier rendu, quand la ref est attachée
return (
{/* 2. Attacher la ref à l'élément DOM */}
);
}
export default FocusInput; Points clés :
- Utilisez
useRef.(null) - Initialisez toujours avec
nullpour les refs DOM. - Effectuez toujours une vérification de nullité (
if (ref.current) { ... }) avant d'accéder aux propriétés ou méthodes deref.current, car elle pourrait encore être `null` lors des premiers rendus ou si l'élément n'est pas encore monté.
Typage des Refs pour stocker des valeurs mutables
Lorsque `useRef` est utilisé pour stocker une valeur mutable qui n'est pas un élément DOM, le typage est souvent plus simple. Vous spécifiez le type de la valeur que vous allez stocker dans .current.
Contrairement aux refs DOM, la valeur initiale n'est généralement pas `null` (sauf si c'est intentionnel). TypeScript peut souvent inférer le type à partir de la valeur initiale, mais il est recommandé de le spécifier explicitement pour plus de clarté, surtout si la valeur peut changer.
Exemple : Stocker un ID de Timer
import React, { useRef, useEffect, useState } from 'react';
function TimerComponent() {
const [count, setCount] = useState(0);
// La ref peut contenir un ID de timer (nombre dans Node, objet dans le navigateur)
// ou null s'il n'y a pas de timer actif.
const intervalRef = useRef(null);
useEffect(() => {
// Démarrer le timer au montage
intervalRef.current = setInterval(() => {
setCount(c => c + 1);
}, 1000);
// Nettoyer le timer au démontage
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, []); // Tableau de dépendances vide
const handleStop = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null; // Mettre à jour la ref
}
};
return (
Compteur : {count}
);
}
export default TimerComponent; Exemple : Stocker une valeur précédente
import React, { useState, useEffect, useRef } from 'react';
function PreviousValueDisplay({ value }: { value: number }) {
// La ref stockera la valeur précédente (un nombre)
// On initialise avec la valeur actuelle, mais on pourrait aussi utiliser undefined
const prevValueRef = useRef(value);
useEffect(() => {
// Mettre à jour la ref APRES le rendu pour stocker la valeur
// qui était présente LORS du rendu précédent.
prevValueRef.current = value;
}, [value]); // Se met à jour quand 'value' change
return (
Valeur actuelle: {value}, Valeur précédente: {prevValueRef.current}
);
}
export default PreviousValueDisplay; Importance de la vérification de `null` pour les Refs DOM
Il est crucial de répéter l'importance de vérifier si ref.current est `null` avant d'y accéder lorsque vous manipulez des refs DOM. Cette vérification est nécessaire car :
- Au premier rendu, la ref n'est pas encore attachée, donc
ref.currentest `null`. - Dans certains scénarios de rendu conditionnel, l'élément DOM auquel la ref est attachée peut ne pas être rendu, laissant
ref.currentà `null`. - Dans les gestionnaires d'événements, surtout ceux qui pourraient être déclenchés pendant le démontage, il est plus sûr de vérifier.
Ne pas effectuer cette vérification est une source fréquente d'erreurs `TypeError: Cannot read properties of null (...)` en production.
Refs et `forwardRef`
Lorsque vous transmettez une ref à un composant enfant en utilisant React.forwardRef, le typage de la ref transmise devient également important. Le deuxième argument de la fonction de rendu de `forwardRef` est la ref, et elle doit être typée correctement, souvent en utilisant le type React.ForwardedRef.
import React, { forwardRef } from 'react';
interface FancyInputProps {
label: string;
// autres props...
}
// Typer la ref transmise
const FancyInput = forwardRef(
({ label, ...props }, ref) => {
return (
);
}
);
export default FancyInput; Conclusion : Des références plus sûres avec TypeScript
Typer vos refs avec `useRef