useRef
est un des hooks fondamental de React. Il permet de nombreuses choses
et il est, à mon sens, pas assez utilisé. Dans cet article on va essayer de
comprendre quelles sont les utilités du useRef
et ses différences avec
useState
.
Documentation de useRef
D'après la documentation React le useRef permet de stocker une valeur qui n'est pas nécessaire pour le rendu.
Usage
const Component = () => {
const ref = useRef(12);
console.log(ref.current); // 12
};
useRef
va retourner une ref object
avec une unique propriété nommée current
qui
contient la valeur stockée. Dans le prochain render la ref sera toujours la même...
il faut la modifier et utiliser la méthode current.current = value
On peut notamment l'utiliser pour récupérer la référence d'un élément du DOM. Dans cette article on ne va pas s'attarder sur cette utilisation. Mais tu peux en savoir plus dans cette vidéo YouTube.
Bref la documentation React l'explique bien mieux que moi donc je te propose de te le faire comprendre visuellement.
Mais pour comprendre useRef
il faut comprendre :
C'est quoi une ref ?
Peux-tu deviner la valeur de value.current
ici :
const value = { current: 0 };
const value2 = value;
const value3 = value2;
value3.current = 1;
Réponse 1
Visuellement ce code donne ça :
value
{"current":0}
value2
{"current":0}
value3
{"current":0}
{"current":0}
ℹ️ En cliquant sur Next tu crées une nouvelle variable qui reprend la valeur précédente.
En cliquant sur "Set current value" tu incrémentes de 1
current
.
Tu vois que toutes les variables changent. Tu as en fait tu as changé la valeur de leur référence (carré orange), et elles partagent toutes la même référence. Elles sont donc toutes impactées par ce changement.
Et là, tu peux légitimement te demander :
Pourquoi
{ current: 0 }
et pas juste 0 ?
Voici le même exemple qu'avant avec 0
:
value
0
0
value2
0
0
value3
0
0
0 est un number, c'est une valeur primitive. J'ai envie de dire qu'une valeur primitive est sa propre référence. Quand tu la changes, tu modifies la référence.
Une référence, c'est un state qui ne change jamais.
Finalement, dans ton code React, on peut facilement les comparer :
const [state] = useState({ current: 0 });
// Égale
const ref = useRef(0);
state.current = 1; // pas de render
ref.current = 1; // pas de render
Par ailleurs c'est pour ça que push
ne sert à rien si tu veux modifier l'état
d'un tableau avec setState
. Push ne modifie pas la ref ! C'est pour ça qu'il
faut utiliser setState([...state, value])
car dans ce cas on recrée une ref.
Voici un exemple d'un state [1,2,3]
avec un bouton qui rajoute 4
pour faire un tableau de [1,2,3,4]
:
state
[1,2,3]
[1,2,3]
[1,2,3]
On voit que quand on change le state, React crée une nouvelle référence et le state pointe sur cette nouvelle référence.
useRef vs useState vs variable
Pour finalement comprendre les différences et les subtilités de nos hooks favoris en React, voici un exemple :
let variable = 0;
const Component = () => {
const [state, setState] = useState(0);
const ref = useRef(0);
const incrementState = () => {
setState(state + 1);
};
const incrementRef = () => {
ref.current += 1;
};
const incrementVariable = () => {
variable += 1;
};
return (
<div>
<button onClick={incrementState}>Increment state ({state})</button>
<button onClick={incrementRef}>Increment ref ({ref.current})</button>
<button onClick={incrementVariable}>Increment variable ({variable})</button>
</div>
);
};
Voici le rendu pour le code ci-dessus. Amuse-toi à cliquer sur increment ref
et
increment variable
plusieurs fois puis clique sur increment state
.
ça donne quoi ? Quand tu cliques sur le useRef
rien ne se passe, pareil pour
la variable. Par contre, à l'instant où tu cliques sur le useState
la valeur du
button useRef
et de la variable change !
Pourquoi ? Car un state
provoquer un rerender qui va automatiquement mettre à
jour le composant. Lorsque le composant va être rendu, il va prendre les valeurs de
useRef
et de la variable à jour.
Les rerenders sont visibles car le composant "bip" en vert
Il faut bien comprendre que la vue n'est update que quand le composant est mis à jour.
Le useRef
permet donc de stocker une valeur, mais elle n'influe pas le render.
Mais quel est l'avantage de useRef
par rapport à une simple variable (comme dans
l'exemple au-dessus du composant) ?
Voici un deuxième exemple, mais ce qui est intéressant, c'est que cette fois-ci,
la variable
et le useRef
n'ont pas le même comportement.
Ce qui vient de se passer c'est que la variable n'est pas liée au composant. C'est une
simple variable que tu pourrais déclarer dans un fichier script.js
random.
La variable garde le même état même si c'est une instance différente.
Faire ce genre de chose est totalement déconseillé car ton composant devient impur. Les pure fonction sont des fonctions qui retournent toujours la même chose si on leur donne les mêmes paramètres. Utiliser des variables externes peut causer des bugs inattendus.
Quand se servir de useRef
useRef est parfait pour stocker des valeurs qui ne sont pas affichées dans la vue.
Comme tu l'as vu avec l'exemple des buttons, ce n'est pas très pratique d'avoir un useRef pour gérer un Counter. Normal, ce n'est pas fait pour.
Si tu veux afficher une valeur, comme la list
précédente → tu utilises un useState.
Quelques exemples concrets :
useDebounce
C'est un hook connu qui permet d'appeler une fonction après un délai.
Dans le cadre d'une search bar tu n'as pas envie de fetch ton API
avec la query à chaque lettre tapée. Avec le hook useDebouce
tu vas
fetch l'API quand l'utilisateur aura fini de taper depuis 1 seconde par
exemple.
Tu peux tester, écris quelque chose et l'alert
se fera 1 seconde après.
Le useRef
me permet ici de stocker la valeur retournée par le time out. Ce
qui me permet de clear dès que la fonction est rappelée. Pourquoi j'utilise un
useRef
ici ? Car je ne souhaite uniquement stocker la valeur, je ne l'affiche nulle part.
C'est possible de le faire avec useState, mais tu vas provoquer des render inutiles. Ce n'est pas la fin du monde, mais c'est comme utiliser une voiture pour faire 100 mètres.
Canvas
J'ai déjà fait un petit canva, où tu peux dessiner.
Voici le code pour ce canva :
const Canvas = () => {
const canvas = useRef(null);
const isDrawing = useRef(false);
const prevMouse = useRef(null);
const startDrawing = (event) => {
isDrawing.current = true;
prevMouse.current = getCoordinates(event, canvas.current);
};
const stopDrawing = () => {
isDrawing.current = false;
prevMouse.current = null;
};
const draw = (event) => {
if (!isDrawing.current) return;
const context = canvas.current?.getContext('2d');
// ... draw line with context
prevMouse.current = mouse;
};
return <canvas ref={canvas} /* ... all events listeners */ />;
};
Dans cet exemple j'utilise canvas
comme ref
pour garder une référence sur le canva.
Et j'utilise aussi les références isDrawing
et prevMouse
pour gérer la fonctionnalité de dessin.
En fait, c'est comme des variables dans mon code et les ref ici sont parfaites, car pour faire ce dessin j'interargis directement avec le DOM et je n'ai pas envie de faire travailler ReactDOM avec des render inutiles !
Conclusion
Dans cet article tu as compris le fonctionnement des références en JavaScript ainsi
que le fonctionnement du hook useRef
. Tu sais maintenant différencier useRef
et
useState
et tu sais même quand et où utiliser une ref
plutôt qu'un state.
Cette article à été créer pour la formation BeginReact.dev !
Recommendations

Written by Melvyn Malherbe
J'ai aidé 200 personnes à apprendre React et Next.js. Je suis un créateur de contenue et un développeur web. Plus de 2'600 personnes reçoivent mes newsletter par email chaque semaine.
En apprendre plus à propos de moi