useRef è un hook React che crea un oggetto ref mutabile con una proprietà .current, conservato tra i render del componente. A differenza di useState, modificare .current non provoca un re-render, rendendo useRef ideale per memorizzare riferimenti DOM, timer e qualsiasi valore che debba persistere tra i render senza ridisegnare l'interfaccia. Secondo la Documentazione React (2025), l'oggetto ref viene creato una volta durante la vita del componente e non cambia tra i render, garantendo la stabilità del riferimento.
Punti chiave
useRef è un hook aggiunto in React 16.8 che restituisce un oggetto ref mutabile con una singola proprietà .current. Il valore iniziale viene assegnato a .current al montaggio del componente. La differenza principale da una variabile normale è che l'oggetto ref sopravvive ai re-render: nei render successivi React non ricrea il ref ma restituisce lo stesso oggetto.
Internamente, useRef utilizza lo stesso meccanismo di useState e useEffect — una lista collegata di hook sul nodo fiber. Tuttavia, a differenza di useState, React non traccia le modifiche all'oggetto ref, non accoda aggiornamenti e non pianifica re-render. Questo rende useRef un hook estremamente leggero, senza impatto sulle prestazioni anche con modifiche frequenti.
Secondo il Team React — Hooks FAQ (2025), useRef è essenzialmente una “scatola” che memorizza un valore. Zucchero sintattico: const ref = useRef(valoreIniziale) equivale a const ref = { current: valoreIniziale } con la differenza che React garantisce che l'oggetto ref sarà lo stesso ad ogni render. Nessuna magia — solo un riferimento stabile gestito da React.
import { useRef } from 'react';
function Component() {
const countRef = useRef(0);
// countRef.current = 0 inizialmente
// countRef.current = 5 dopo la mutazione
// Nessun re-render si verifica!
}
Il caso d'uso più comune di useRef è ottenere l'accesso diretto a un elemento DOM. React assegna a elementRef.current un riferimento al nodo DOM dopo il montaggio del componente. Ciò è necessario per focalizzare un input, misurare le dimensioni degli elementi, integrarsi con librerie di animazione e librerie che non utilizzano il rendering React.
React gestisce automaticamente i riferimenti ref al DOM: al montaggio assegna il nodo DOM effettivo, allo smontaggio lo annulla (lo imposta a null). Ciò garantisce che .current abbia sempre il valore aggiornato e previene perdite di memoria attraverso riferimenti pendenti a elementi rimossi. Non è richiesta pulizia manuale.
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
// Focusare l'input dopo il montaggio del componente
inputRef.current?.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
Secondo la documentazione React — Refs e DOM (2025), non usare ref per operazioni dichiarative — aprire/chiudere modali, gestire la visibilità. Per questi scopi esistono state e props. Le ref sono destinate a operazioni imperative che non possono essere espresse dichiarativamente: focus, selezione di testo, integrazione con librerie di terze parti.
Il secondo caso d'uso più importante è la memorizzazione di valori arbitrari che devono persistere tra i render ma le cui modifiche non devono attivare un re-render. Esempi tipici: identificatori di timer (setInterval/setTimeout), flag di annullamento richieste, valori precedenti di props per confronto e qualsiasi dato che non influisca sull'output dell'interfaccia.
Ciò è particolarmente utile in useEffect: useRef memorizza l'identificatore del timer e la pulizia lo elimina. Se timerId fosse memorizzato in useState, ogni chiamata a setTimerId provocherebbe un re-render non necessario, non richiesto né per la logica né per l'interfaccia. useRef risolve questo problema senza overhead e senza re-render non necessari.
function Timer() {
const intervalRef = useRef(null);
const start = () => {
intervalRef.current = setInterval(() => {
console.log('tic');
}, 1000);
};
const stop = () => {
clearInterval(intervalRef.current);
};
useEffect(() => stop, []);
return <><button onClick={start}>Start</button><button onClick={stop}>Stop</button></>;
}
Il dilemma principale — scegliere tra useRef e useState — si risolve con una domanda: “È necessario un re-render quando il valore cambia?”. Se sì — useState. Se no — useRef. useState memorizza lo stato che influenza l'output del componente; useRef memorizza i dati necessari per la logica interna ma che non influenzano l'interfaccia.
In pratica, gli sviluppatori usano spesso useRef per memorizzare callback al fine di evitare problemi con le chiusure. Ad esempio, se useEffect si iscrive a un evento e il callback necessita dello stato corrente — memorizza il callback in useRef. Ad ogni render, aggiorna ref.current con una nuova funzione, e l'effetto invocherà sempre il callback fresco senza doversi re-iscrivere.
| Criterio | useRef | useState |
|---|---|---|
| Re-render | Non attiva al cambiamento | Attiva ad ogni setState |
| Mutazione | Diretta: ref.current = valore | Tramite setter: setState(valore) |
| Uso in JSX | Non usato (nessun effetto) | Usato nell'output del componente |
| Esempio | Timer, riferimenti DOM, valori precedenti | Dati modulo, stato UI, flag |
Esiste un anti-pattern: usare useRef per dati necessari in JSX ma le cui modifiche non devono causare re-render. Ciò porta a desincronizzazione — l'interfaccia mostra dati vecchi mentre ref.current è già nuovo. Se il valore viene visualizzato nell'interfaccia — usa useState. Se usato solo internamente — useRef.
La combinazione useRef + useEffect è il modello standard per tracciare i valori precedenti delle props. Memorizza il valore precedente in ref, confrontalo con il valore corrente in useEffect e prendi decisioni basate sulla differenza. Ciò è particolarmente utile nelle animazioni quando hai bisogno di sapere quale valore aveva prima della modifica.
function PriceDisplay({ price }) {
const prevPriceRef = useRef(price);
useEffect(() => {
const prevPrice = prevPriceRef.current;
if (price > prevPrice) {
animateUp();
} else if (price < prevPrice) {
animateDown();
}
prevPriceRef.current = price;
}, [price]);
return <span>${price}</span>;
}
Secondo la documentazione React — Hooks FAQ (2025), questo modello è chiamato “modello del valore precedente”. Funziona perché useRef conserva il valore tra i render e useEffect viene eseguito dopo la conferma delle modifiche. Prima il DOM viene aggiornato con il nuovo price, poi useEffect lo confronta con il precedente (ancora in ref) e aggiorna ref.current al valore corrente.
L'errore più frequente è leggere ref.current durante la fase di render per calcolare JSX. Poiché modificare ref.current non attiva un re-render, il componente potrebbe utilizzare un valore obsoleto. Se .current partecipa all'output dell'interfaccia — usa useState. Se devi sincronizzare ref e state, usa useEffect per aggiornare lo state da ref.
// ❌ Non leggere ref.current durante il render per la visualizzazione
function BadComponent() {
const valRef = useRef(0);
return <p>{valRef.current}</p>; // NON verrà aggiornato alla mutazione
}
// ✅ Usa state per la visualizzazione, ref per la logica
function GoodComponent() {
const [val, setVal] = useState(0);
const valRef = useRef(0);
return <p>{val}</p>;
}
Un altro errore comune è usare useRef come unico modo per memorizzare lo stato in un componente quando i dati influenzano effettivamente l'interfaccia. Gli sviluppatori scelgono useRef per evitare re-render “non necessari”, ma finiscono con un'interfaccia che non si aggiorna. L'approccio corretto: usa useState per i dati dell'interfaccia e useRef solo per valori ausiliari che non partecipano al rendering.
Domande frequenti
Sì, è un modello comune — il modello dello stato precedente. Crea un ref e aggiornalo in useEffect ad ogni cambiamento del valore tracciato. Tra il render e l'effetto, ref.current contiene il valore precedente, che può essere confrontato con quello corrente. Ciò non richiede re-render aggiuntivi e funziona con qualsiasi tipo di dato.
React assegna a ref.current il valore del nodo DOM solo dopo che l'elemento è stato renderizzato e aggiunto al DOM reale. Durante il primo render, il componente non è ancora montato, quindi ref.current è uguale al valore iniziale (null). L'accesso al DOM tramite ref.current è possibile solo in useEffect o nei gestori di eventi chiamati dopo il montaggio.
createRef crea un nuovo oggetto ref ad ogni render — dovrebbe essere usato solo nei componenti a classe. useRef crea il ref una volta e restituisce lo stesso oggetto in tutti i render successivi. Nei componenti funzionali usa esclusivamente useRef; createRef causerà la perdita del valore al re-render perché l'oggetto verrà ricreato.
Sì, un oggetto ref può essere passato come una prop normale: <Child inputRef={inputRef} />. Il componente figlio lo usa tramite inputRef.current. Tuttavia, per passare un ref direttamente all'elemento DOM di un componente figlio, usa forwardRef — un HOC che consente di inoltrare ref tramite props. Senza forwardRef, il ref non sarà automaticamente collegato all'elemento DOM all'interno del componente figlio.
Collega un ref all'elemento, poi in useEffect leggi ref.current.getBoundingClientRect() o ref.current.offsetWidth / offsetHeight. Per il tracciamento reattivo dei cambiamenti di dimensione, usa ResizeObserver all'interno di useEffect: crea un observer, iscriviti ai cambiamenti e aggiorna lo state con le nuove dimensioni. Non dimenticare di disconnettere l'observer nella pulizia.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche