logo oujood
🔍

useRef : Accédez Directement aux Éléments DOM ou Conservez des Valeurs Mutables

OUJOOD.COM

Introduction

Le Hook `useRef` est utilisé pour deux objectifs principaux en React :

  1. Accéder directement aux éléments DOM : Permet de manipuler des éléments HTML sans passer par des méthodes comme `findDOMNode`.
  2. Conserver des valeurs mutables : Vous pouvez stocker des informations qui ne déclenchent pas de re-render lorsqu'elles sont modifiées.

Dans ce chapitre, nous allons explorer :

  • Comment créer et utiliser une référence avec `useRef`.
  • Des exemples pratiques pour illustrer ses fonctionnalités.

1. Qu'est-ce que `useRef` ?

`useRef` est un Hook React qui retourne un objet mutable contenant une propriété appelée `.current`. Cette propriété peut être utilisée pour :

  • Stocker des références aux éléments DOM : Par exemple, pour mettre le focus sur un champ de saisie après un clic.
  • Conserver des valeurs mutables : Utile pour stocker des données qui ne doivent pas déclencher de re-render lorsqu'elles changent.

Contrairement à `useState`, `useRef` ne provoque pas de mise à jour de l'interface utilisateur lorsque sa valeur change. Cela le rend parfait pour certaines situations où une mise à jour immédiate n'est pas nécessaire.

2. Utilisation de useRef pour gérer le focus sur un champ input`

Voici un exemple simple où nous utilisons `useRef` pour mettre le focus automatiquement sur un champ de saisie lorsque l'utilisateur clique sur un bouton :

📋 Copier le code

import React, { useRef } from 'react';
import { createRoot } from 'react-dom/client';

function FocusInput() {
const inputRef = useRef(null); // Création d'une référence vers un élément DOM

function handleClick() {
inputRef.current.focus(); // Met le focus sur l'élément DOM lié à la référence
}

return (
<div>
<input type="text" ref={inputRef} placeholder="Cliquez ici pour me sélectionner..." />
<button onClick={handleClick}>Mettre le focus</button>
</div>
);
}

const root = createRoot(document.getElementById('root'));
root.render(<FocusInput />);

Explication détaillée ligne par ligne :

  1. import React, { useRef } from 'react'; :
    • Nous importons React ainsi que le Hook useRef.
    • useRef permet de créer une référence mutable qui persiste tout au long du cycle de vie du composant.
  2. const inputRef = useRef(null); :
    • Cette ligne crée une référence appelée inputRef, initialisée avec null.
    • La propriété .current de cette référence sera utilisée pour pointer vers l'élément DOM lié.
  3. function handleClick() { ... } :
    • Cette fonction est appelée lorsque l'utilisateur clique sur le bouton.
    • inputRef.current.focus() : La méthode focus() est appelée sur l'élément DOM pointé par inputRef.current, mettant ainsi le focus sur le champ de saisie.
  4. <input type="text" ref={inputRef} /> :
    • Ce champ de saisie est lié à la référence inputRef via l'attribut ref.
    • Lorsque le composant est monté, inputRef.current pointera vers l'élément DOM du champ de saisie.
  5. <button onClick={handleClick}>Mettre le focus</button> :
    • Ce bouton appelle la fonction handleClick lorsqu'il est cliqué.
    • Cela mettra le focus sur le champ de saisie associé à la référence inputRef.
  6. const root = createRoot(document.getElementById('root')); :
    • Cette ligne crée une instance de racine React appelée root.
    • document.getElementById('root') spécifie l'élément HTML où le composant sera inséré.
  7. root.render(<FocusInput />); :
    • Rend le composant FocusInput dans l'élément HTML ayant l'id root.
    • Utilise createRoot pour garantir une compatibilité avec React 18 et versions ultérieures.

Pourquoi utiliser useRef ici ?

  • useRef permet d’accéder directement à un élément DOM sans provoquer de re-render du composant.
  • Contrairement à useState, useRef ne déclenche pas de re-rendu lorsqu'il est mis à jour.
  • C'est utile pour des manipulations comme le focus, la lecture/écriture de valeurs DOM, ou encore l'intégration avec des bibliothèques tierces.

Améliorations possibles :

  • Ajouter du style pour une meilleure expérience utilisateur.
  • Gérer les cas où l’élément inputRef.current pourrait être null.
  • Ajouter un message dynamique lorsque l'input reçoit le focus.

Version améliorée avec gestion d'état :

Si vous voulez informer l'utilisateur quand l'input a le focus :

📋 Copier le code

import React, { useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';

function FocusInput() {
const inputRef = useRef(null);
const [message, setMessage] = useState("");

function handleClick() {
inputRef.current.focus();
setMessage("L'input est sélectionné !");
}

return (
<div>
<input 
type="text" 
ref={inputRef} 
placeholder="Cliquez ici pour me sélectionner..."
onBlur={() => setMessage("")} // Réinitialisation du message quand l'input perd le focus
/>
<button onClick={handleClick}>Mettre le focus</button>
<p>{message}</p>
</div>
);
}

const root = createRoot(document.getElementById('root'));
root.render(<FocusInput />);

Cela rend l'expérience utilisateur plus interactive en affichant un message lorsque l'input est sélectionné. 🚀

3. Conservation de Valeurs Mutables avec `useRef`

En plus de manipuler des éléments DOM, `useRef` peut être utilisé pour conserver des valeurs mutables entre les re-renders sans déclencher de mise à jour de l'interface utilisateur. Voici un exemple où nous conservons un compteur dans une référence :

📋 Copier le code

import React, { useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';

function Compteur() {
const [compte, setCompte] = useState(0); // Gestion de l'état affiché
const compteurRef = useRef(0); // Référence pour conserver une valeur mutable

function incrementer() {
compteurRef.current += 1; // Incrémente la valeur de la référence
setCompte(compteurRef.current); // Met à jour l'état affiché avec la valeur actuelle de la référence
}

return (
<div>
<p>Vous avez cliqué {compte} fois.</p>
<button onClick={incrementer}>Incrémenter</button>
</div>
);
}

const root = createRoot(document.getElementById('root'));
root.render(<Compteur />);

Explication détaillée ligne par ligne :

  1. const compteurRef = useRef(0); :
    • Cette ligne crée une référence appelée compteurRef, initialisée avec la valeur 0.
    • La propriété .current de cette référence peut être modifiée sans déclencher de re-render du composant.
  2. compteurRef.current += 1; :
    • Cette ligne incrémente la valeur de la référence compteurRef.current de 1.
    • Contrairement à `useState`, cette modification ne provoque pas de mise à jour immédiate de l'interface utilisateur.
  3. setCompte(compteurRef.current); :
    • Cette ligne met à jour l'état affiché (compte) avec la valeur actuelle de la référence compteurRef.current.
    • Seule cette mise à jour de l'état déclenche un re-render du composant.
  4. <button onClick={incrementer}>Incrémenter</button> :
    • Ce bouton appelle la fonction incrementer lorsqu'il est cliqué.
    • Cela incrémente la valeur de la référence compteurRef et met à jour l'état affiché.

Pourquoi utiliser useRef ici ?

  • Permet de stocker une valeur mutable sans déclencher un re-render.
  • Améliore les performances en évitant des mises à jour inutiles.

Version améliorée avec réinitialisation :

📋 Copier le code

import React, { useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';

function Compteur() {
const [compte, setCompte] = useState(0);
const compteurRef = useRef(0);

function incrementer() {
compteurRef.current += 1;
setCompte(compteurRef.current);
}

function reinitialiser() {
compteurRef.current = 0;
setCompte(0);
}

return (
<div>
<p>Vous avez cliqué {compte} fois.</p>
<button onClick={incrementer}>Incrémenter</button>
<button onClick={reinitialiser}>Réinitialiser</button>
</div>
);
}

const root = createRoot(document.getElementById('root'));
root.render(<Compteur />);

Ce composant permet d'incrémenter un compteur et de le réinitialiser en utilisant useRef et useState. 🚀

4. Comparaison entre `useState` et `useRef`

Bien qu'ils puissent sembler similaires, `useState` et `useRef` ont des usages distincts. Voici leurs différences principales :

Aspect useState useRef
Fonctionnement Déclenche un re-render lorsque sa valeur change. Ne déclenche pas de re-render lorsque sa valeur change.
Utilisation Utilisé pour gérer des états qui affectent l'interface utilisateur. Utilisé pour conserver des valeurs mutables ou accéder directement aux éléments DOM.
Exemple Typique Gestion d'un compteur affiché sur l'écran. Mise au focus d'un champ de saisie ou stockage d'une valeur temporaire.

5. Exemple Pratique : Compteur avec Conservation de Valeurs

Imaginons que vous souhaitez créer un compteur qui conserve son ancienne valeur même après un re-render. Voici comment cela peut être fait :

📋 Copier le code

import React, { useRef, useState } from 'react';
import { createRoot } from 'react-dom/client';

function CompteurPersistant() {
const [compte, setCompte] = useState(0); // État affiché
const dernierCompteRef = useRef(0); // Référence pour conserver la dernière valeur

function incrementer() {
setCompte(compte + 1); // Met à jour l'état affiché
dernierCompteRef.current = compte; // Conserve la dernière valeur dans la référence
}

return (
<div>
<p>Vous avez cliqué {compte} fois.</p>
<p>Dernière valeur avant l'incrément : {dernierCompteRef.current}</p>
<button onClick={incrementer}>Incrémenter</button>
</div>
);
}

const root = createRoot(document.getElementById('root'));
root.render(<CompteurPersistant />);

Explication détaillée ligne par ligne :

  1. const dernierCompteRef = useRef(0); :
    • Cette ligne crée une référence appelée dernierCompteRef, initialisée avec la valeur 0.
    • Elle servira à conserver la dernière valeur du compteur avant chaque incrément.
  2. dernierCompteRef.current = compte; :
    • Cette ligne met à jour la propriété .current de la référence dernierCompteRef avec la valeur actuelle de compte.
    • Cette mise à jour ne déclenche pas de re-render, car useRef est conçu pour conserver des valeurs mutables.
  3. <p>Dernière valeur avant l'incrément : {dernierCompteRef.current}</p> :
    • Cet élément affiche dynamiquement la valeur conservée dans la référence dernierCompteRef.current.

Conclusion

Vous avez maintenant appris à utiliser le Hook `useRef` pour deux objectifs principaux : accéder directement aux éléments DOM et conserver des valeurs mutables sans déclencher de re-render. Ces fonctionnalités rendent `useRef` particulièrement utile dans des scénarios où une interaction directe avec le DOM ou la persistance de valeurs est requise.

Prochain chapitre : useReducer