useRef est un Hook React qui vous permet de rĂ©fĂ©rencer une valeur qui n’est pas nĂ©cessaire au code du rendu lui-mĂȘme.

const ref = useRef(initialValue)

Référence

useRef(initialValue)

Appelez useRef au niveau racine de votre composant pour déclarer une ref.

import { useRef } from 'react';

function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...

Voir d’autres exemples ci-dessous.

ParamĂštres

  • initialValue : la valeur initiale pour la propriĂ©tĂ© current de l’objet ref. Elle peut ĂȘtre de n’importe quel type. Cet argument est ignorĂ© aprĂšs le rendu initial.

Valeur renvoyée

useRef renvoie un objet dotĂ© d’une unique propriĂ©tĂ© :

  • current : elle vaut initialement la initialValue que vous avez passĂ©e. Vous pourrez ensuite la modifier. Si vous passez l’objet ref Ă  React en tant que prop ref d’un nƓud JSX, React dĂ©finira automatiquement sa propriĂ©tĂ© current.

Lors des rendus ultĂ©rieurs, useRef renverra le mĂȘme objet.

Limitations

  • Vous pouvez modifier la propriĂ©tĂ© ref.current. Contrairement Ă  l’état, elle est modifiable. En revanche, si vous y stockez un objet nĂ©cessaire au rendu (par exemple un morceau de votre Ă©tat), vous ne devriez pas modifier cet objet.
  • Lorsque vous modifiez la propriĂ©tĂ© ref.current, React ne refait pas de rendu de votre composant. React n’est pas au courant de vos modifications parce qu’une ref est un objet JavaScript brut.
  • Évitez d’écrire ou mĂȘme de lire ref.current lors du rendu, sauf pour l’initialiser. Ça rendrait le comportement de votre composant imprĂ©visible.
  • En Mode Strict, React appellera votre fonction composant deux fois afin de vous aider Ă  repĂ©rer des impuretĂ©s accidentelles. Ce comportement est limitĂ© au dĂ©veloppement et n’affecte pas la production. Chaque objet ref sera créé deux fois, mais une de ses versions sera ignorĂ©e. Si votre fonction composant est pure (ce qui devrait ĂȘtre le cas), ça n’affectera en rien son comportement.

Utilisation

Référencer une valeur avec une ref

Appelez useRef au niveau racine de votre composant pour déclarer une ou plusieurs refs.

import { useRef } from 'react';

function Stopwatch() {
const intervalRef = useRef(0);
// ...

useRef renvoie un objet ref avec une unique propriété current initialement définie à la valeur initiale que vous avez fournie.

Lors des rendus ultĂ©rieurs, useRef renverra le mĂȘme objet. Vous pouvez en modifier la propriĂ©tĂ© current pour stocker une information que vous relirez plus tard. Ça vous rappelle peut-ĂȘtre l’état, mais il y a une diffĂ©rence fondamentale.

Modifier une ref ne redĂ©clenche pas le rendu. Ça signifie que les refs sont idĂ©ales pour stocker des informations qui n’affectent pas le rĂ©sultat visuel de votre composant. Par exemple, si vous devez stocker un identifiant de timer et le rĂ©cupĂ©rer plus tard, mettez-le dans une ref. Pour mettre Ă  jour la valeur d’une ref, vous devez modifier manuellement sa propriĂ©tĂ© current :

function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}

Par la suite, vous pouvez lire l’identifiant du timer depuis la ref afin de dĂ©commissionner le timer :

function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}

En utilisant une ref, vous garantissez que :

  • Vous pouvez stocker de l’information d’un rendu Ă  l’autre (contrairement aux variables classiques, rĂ©initialisĂ©es Ă  chaque rendu).
  • La modifier ne dĂ©clenche pas un nouveau rendu (contrairement aux variables d’état, qui dĂ©clenchent un nouveau rendu).
  • L’information reste locale Ă  chaque instance de votre composant (contrairement aux variables extĂ©rieures, qui sont partagĂ©es).

Modifier une ref ne dĂ©clenche pas de nouveau rendu, de sorte que les refs sont inadaptĂ©es au stockage d’information que vous souhaitez afficher Ă  l’écran. Utilisez plutĂŽt des variables d’état pour ça. Apprenez comment choisir entre useRef et useState.

Exemples de référencements de valeurs avec useRef

Exemple 1 sur 2 Â·
Compteur de clics

Ce composant utilise une ref pour garder le compte du nombre de fois qu’un bouton a Ă©tĂ© cliquĂ©. Notez qu’on peut parfaitement utiliser une ref plutĂŽt qu’une variable d’état dans ce cas, puisque le compteur n’est lu et Ă©crit qu’au sein d’un gestionnaire d’évĂ©nement.

import { useRef } from 'react';

export default function Counter() {
  let ref = useRef(0);

  function handleClick() {
    ref.current = ref.current + 1;
    alert('Vous avez cliquĂ© ' + ref.current + ' fois !');
  }

  return (
    <button onClick={handleClick}>
      Cliquez ici !
    </button>
  );
}

Si vous affichiez {ref.current} dans le JSX, le nombre ne serait pas mis Ă  jour au clic. C’est parce que la redĂ©finition de ref.current ne dĂ©clenche pas de nouveau rendu. Les informations utilisĂ©es par le rendu devraient plutĂŽt ĂȘtre stockĂ©es dans des variables d’état.

PiĂšge

N’écrivez pas et ne lisez pas ref.current lors du rendu.

React s’attend Ă  ce que le corps de votre composant se comporte comme une fonction pure :

  • Si les entrĂ©es (les props, l’état et le contexte) sont les mĂȘmes, votre composant devrait renvoyer exactement le mĂȘme JSX.
  • L’appeler dans un ordre diffĂ©rent ou avec des arguments diffĂ©rents ne devrait pas affecter les rĂ©sultats des autres appels.

Lire ou Ă©crire une ref lors du rendu va Ă  l’encontre de ces attentes.

function MyComponent() {
// ...
// đŸš© N'Ă©crivez pas une ref pendant le rendu
myRef.current = 123;
// ...
// đŸš© Ne lisez pas une ref pendant le rendu
return <h1>{myOtherRef.current}</h1>;
}

Vous pouvez plutĂŽt lire ou Ă©crire des refs au sein de gestionnaires d’évĂ©nements ou d’Effets.

function MyComponent() {
// ...
useEffect(() => {
// ✅ Vous pouvez lire ou Ă©crire des refs dans un Effet
myRef.current = 123;
});
// ...
function handleClick() {
// ✅ Vous pouvez lire ou Ă©crire des refs dans un gestionnaire d'Ă©vĂ©nement
doSomething(myOtherRef.current);
}
// ...
}

Si vous devez lire ou écrire quelque chose durant le rendu, utilisez plutÎt un état.

Lorsque vous enfreignez ces rĂšgles, votre composant restera peut-ĂȘtre opĂ©rationnel, mais la plupart des nouvelles fonctionnalitĂ©s que nous sommes en train d’ajouter Ă  React dĂ©pendent de ces attentes. Apprenez plutĂŽt comment garder vos composants purs.


Manipuler le DOM avec une ref

Il est particuliùrement courant d’utiliser une ref pour manipuler le DOM. React prend nativement en charge ce cas de figure.

Commencez par dĂ©clarer un objet ref avec une valeur initiale Ă  null :

import { useRef } from 'react';

function MyComponent() {
const inputRef = useRef(null);
// ...

Passez ensuite votre objet ref comme prop ref du JSX d’un nƓud DOM que vous souhaitez manipuler :

// ...
return <input ref={inputRef} />;

Une fois que React a créé le nƓud DOM et l’a mis Ă  l’écran, React dĂ©finira la propriĂ©tĂ© current de votre objet ref pour pointer sur ce nƓud DOM. Vous pouvez dĂ©sormais accĂ©der au nƓud DOM de l’<input> et appeler des mĂ©thodes telles que focus() :

function handleClick() {
inputRef.current.focus();
}

React remettra la propriĂ©tĂ© current Ă  null lorsque le nƓud sera retirĂ© de l’écran.

Découvrez plus en détails la manipulation du DOM avec des refs.

Exemples de manipulation du DOM avec useRef

Exemple 1 sur 4 Â·
Activer un champ

Dans cet exemple, cliquer sur le bouton activera le champ de saisie :

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Activer le champ de saisie
      </button>
    </>
  );
}


Éviter de recrĂ©er le contenu de la ref

React sauvegardera la valeur initiale de la ref au premier rendu, puis l’ignorera lors des rendus ultĂ©rieurs.

function Video() {
const playerRef = useRef(new VideoPlayer());
// ...

MĂȘme si le rĂ©sultat de new VideoPlayer() n’est utilisĂ© que lors du rendu initial, vous appelez quand mĂȘme cette fonction Ă  chaque rendu. Ça peut gĂącher les performances si cette crĂ©ation d’objet est coĂ»teuse.

Pour rĂ©soudre ça, utilisez plutĂŽt une initialisation conditionnelle, comme ceci :

function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...

En temps normal, lire ou Ă©crire ref.current lors du rendu est interdit. Ceci dit, c’est acceptable dans ce cas prĂ©cis car le rĂ©sultat sera toujours le mĂȘme, et que la condition n’est vĂ©rifiĂ©e que lors de l’initialisation, ce qui la rend pleinement prĂ©visible.

En détail

Comment Ă©viter des vĂ©rifications de null lors d’appels ultĂ©rieurs Ă  useRef

Si vous utilisez un vĂ©rificateur de types et souhaitez ne pas toujours avoir Ă  vĂ©rifier le cas null, vous pouvez plutĂŽt tenter une approche comme celle-ci :

function Video() {
const playerRef = useRef(null);

function getPlayer() {
if (playerRef.current !== null) {
return playerRef.current;
}
const player = new VideoPlayer();
playerRef.current = player;
return player;
}

// ...

Ici, la playerRef elle-mĂȘme peut ĂȘtre null. En revanche, vous devriez arriver Ă  convaincre votre vĂ©rificateur de types qu’il n’y a aucun scĂ©nario dans lequel getPlayer() renvoie null. Utilisez alors getPlayer() dans vos gestionnaires d’évĂ©nements.


Dépannage

Je n’arrive pas Ă  obtenir une ref sur un composant personnalisĂ©

Si vous tentez de passer une ref Ă  votre propre composant, comme ceci :

const inputRef = useRef(null);

return <MyInput ref={inputRef} />;


vous obtiendrez peut-ĂȘtre une erreur dans la console :

Console
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

(«  Avertissement : les fonctions composants ne peuvent pas recevoir de refs. Toute tentative d’accĂ©der Ă  cette ref Ă©chouera. Souhaitiez-vous utiliser React.forwardRef() ? », NdT)

Par dĂ©faut, vos propres composants n’exposent pas de refs vers les nƓuds DOM qu’ils contiennent.

Pour corriger ça, trouvez le composant vers lequel vous souhaitez obtenir une ref :

export default function MyInput({ value, onChange }) {
return (
<input
value={value}
onChange={onChange}
/>
);
}

Enrobez-le alors dans un forwardRef comme ceci :

import { forwardRef } from 'react';

const MyInput = forwardRef(({ value, onChange }, ref) => {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
});

export default MyInput;

Le composant parent peut désormais obtenir une ref vers lui.

Explorez plus avant comment accĂ©der au nƓuds DOM d’un autre composant.