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.