useRef
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 lainitialValue
que vous avez passée. Vous pourrez ensuite la modifier. Si vous passez l’objetref
à React en tant que propref
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
.
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.
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.
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
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 :
(« 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.