03/01/2025REACT

Quand et pourquoi utiliser le hook useRef ?

📌

Le hook UseRef équivaut à une variable qui, lorsqu’on la met à jour, na va pas provoquer de re render du composant.

Caractéristiques

Mise à jour du ref

Pour mettre à jour le ref, on se sert de son unique key current :

ref.current = 1

Différence d’une variable locale const a = 1

Lorsqu’une variable locale est mise à jour, elle ne provoque pas de nouveau rendu. MAIS, lors d’un re render d’un composant, une variable locale est recréée de 0 à nouveau.

Différence d’un state

Le ref et le state sont similaires sur le fait que lors d’un re render, leur valeur n’est pas réinitialisée. MAIS, la mise à jour d’un state provoque le re render du composant.

Cas d’utilisations

Puisque la mise à jour d’une ref ne provoque pas de nouveau rendu, on ne va s’en servir que s’il n’est pas affiché dans le DOM.

Conserver la valeur précédente d’un state

UseRef sera utile si nous souhaitons conserver un historique d’un state, pour s’en servir dans une fonction tierce, par exemple.

Ci-dessous, si prevValue avait été une variable locale (let prevValue = 0), il y aurait toujours eu 0 d’affiché.

Explication : Nous mettons à jour prevValue lorsque notre state lui-même change. Or, lorsqu’un state est mis à jour, il provoque un re render. Or², lorsqu’un composant re render, toute variable locale est réinitialisée (ici 0).

On aurait pu utiliser un autre state, mais cela provoque des rendus inutiles, alors que nous ne nous en servons même pas dans le DOM.

Solution : Transformer notre variable locale en une ref → la variable ne sera pas réinitialisée entre les rendus.

export default function App() {
  const prevValue = useRef(0);
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("count:", count, "prevValue:", prevValue.current);
  }, [prevValue, count]);

  return (
    <div className="App">
      <p>{count}</p>
      <button onClick={() => {
          setCount(prev => {
            prevValue.current = prev;
            return prev + 1;
          });
        }}
      >
        Increment
      </button>
    </div>
  );
}

Référence d’un élément du DOM

Pour sélectionner un élément du DOM, on pourrait lui attribuer un id, puis utiliser document.querySelector(#id).

Mais ce n’est pas le mieux à faire dans React. Au lieu de ça, on va lui attribuer une ref, puis on pourra le modifier à sa guise avec le ref.current.

const ref = useRef(null);

useEffect(() => {
	ref.current.value = "valeur";
}, []);

return <input ref={ref} value=""/>

Savoir si le composant a déjà été rendu

Pour x raison, un composant peut être rendu plusieurs fois lors de son chargement. Or, si par exemple, un call api a lieu dans ce useEffect, on va vouloir l’empêcher s’il a déjà eu lieu.

const firstRender = useRef(true);

useEffect(() => {
    const getData = () => {
        fetch('...')
    }

    if (firstRender.current) {
        getData();
        firstRender.current = false;
    }
}, [])

Démonstration

Dans l’exemple ci-dessous, si on clique sur le bouton pour incrémenter la ref, il sera toujours affiché 0, car la mise à jour du ref ne provoque pas de re render.

C’est seulement lorsque l’on va cliquer sur le bouton du state que le rendu sera mis à jour, et on aura par exemple, 2 pour le ref (si on a cliqué 2 fois jusqu’à maintenant), et 1 pour le state.

const ref = useRef(0);
const [counter, setCounter] = useState(0);

return <>
	<button onClick={() => (ref.current += 1)}>Increment ref</button>
	{ref.current}
  <button onClick={() => setCounter(counter + 1)}>Increment state</button>
	{counter}
</>;