Contactez-nous

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 :

  1. Accéder directement aux noeuds du DOM (pour gérer le focus, mesurer des éléments, intégrer des bibliothèques non-React, etc.).
  2. 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 null pour les refs DOM.
  • Effectuez toujours une vérification de nullité (if (ref.current) { ... }) avant d'accéder aux propriétés ou méthodes de ref.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.current est `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()` est essentiel pour exploiter pleinement la sécurité offerte par TypeScript lors de l'utilisation de ce hook puissant. Que ce soit pour garantir l'accès sûr aux méthodes et propriétés des éléments DOM (en n'oubliant pas le type `| null` et les vérifications associées) ou pour assurer la cohérence des valeurs mutables que vous stockez, le typage des refs prévient des erreurs d'exécution courantes et améliore la clarté et la maintenabilité de votre code React.