useRef — este un hook React care creează un obiect ref mutabil cu proprietatea .current, păstrat între redările componentului. Spre deosebire de useState, modificarea .current nu provoacă re-rendare, ceea ce face useRef ideal pentru stocarea referințelor DOM, timerelor și oricăror valori care trebuie să supraviețuiască redărilor fără a redesena UI. Conform React Documentation (2025), obiectul ref este creat o dată pe durata de viață a componentului și nu se schimbă între redări, garantând stabilitatea referinței.
Principalele puncte
useRef — este un hook adăugat în React 16.8, care returnează un obiect ref mutabil cu o singură proprietate .current. Valoarea inițială este atribuită .current la montarea componentului. Diferența principală față de o variabilă obișnuită — obiectul ref supraviețuiește re-rendărilor: la re-rendare, React nu recrează ref-ul, ci returnează același obiect.
Implementarea internă a useRef folosește același mecanism ca useState și useEffect — o listă înlănțuită de hook-uri pe nodul fiber. Totuși, spre deosebire de useState, React nu urmărește modificările obiectului ref, nu pune actualizări în coadă și nu planifică re-rendarea. Acest lucru face useRef un hook extrem de ușor, care nu afectează performanța chiar și la modificări frecvente.
Conform React Team — Hooks FAQ (2025), useRef este în esență o «cutie» care stochează o valoare. Zahăr sintactic: const ref = useRef(initialValue) este echivalent cu const ref = { current: initialValue } cu diferența că React garantează că obiectul ref va fi același la fiecare redare. Nimic magic — doar o referință stabilă gestionată de React.
import { useRef } from 'react';
function Component() {
const countRef = useRef(0);
// countRef.current = 0 inițial
// countRef.current = 5 după mutare
// Nu are loc re-rendarea!
}
Cel mai comun scenariu de utilizare a useRef — obținerea accesului direct la elementul DOM. React atribuie elementRef.current referința la nodul DOM după montarea componentului. Acest lucru este necesar pentru focusarea input-ului, măsurarea dimensiunilor elementului, integrarea cu bibliotecile de animații și bibliotecile care nu folosesc redarea React.
React gestionează automat referințele ref la DOM: la montare atribuie nodul DOM real, la demontare îl resetează (setează null). Acest lucru garantează că în .current există întotdeauna o valoare actualizată și previne scurgerile de memorie prin referințe «atârnate» către elemente șterse. Nu este necesară nicio curățare manuală.
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
// Focus input după montarea componentului
inputRef.current?.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
Conform React — Refs and DOM documentation (2025), nu folosi ref pentru operații declarative — deschiderea/închiderea modalurilor, gestionarea vizibilității. În aceste scopuri există state și props. Ref-urile sunt destinate operațiilor imperative care nu pot fi exprimate declarativ: focus, selectare text, integrare cu biblioteci terțe.
Al doilea scenariu ca importanță — stocarea valorilor arbitrare care trebuie păstrate între redări, dar a căror modificare nu ar trebui să provoace re-rendarea. Exemple tipice: identificatori de timere (setInterval/setTimeout), flaguri pentru anularea cererilor, valori anterioare ale props-urilor pentru comparație și orice date care nu afectează ieșirea UI.
Acest lucru este util în special în useEffect: useRef stochează identificatorul timer-ului, iar cleanup-ul îl șterge. Dacă timerId este stocat în useState, fiecare apel setTimerId ar provoca o re-rendare inutilă care nu este necesară nici pentru logică, nici pentru UI. useRef rezolvă această problemă fără overhead și fără redesenări inutile.
function Timer() {
const intervalRef = useRef(null);
const start = () => {
intervalRef.current = setInterval(() => {
console.log('tictac');
}, 1000);
};
const stop = () => {
clearInterval(intervalRef.current);
};
useEffect(() => stop, []);
return <><button onClick={start}>Start</button><button onClick={stop}>Stop</button></>;
}
Dilema principală — alegerea între useRef și useState — se rezolvă cu o întrebare: «Este necesară re-rendarea la modificarea valorii?». Dacă da — useState. Dacă nu — useRef. useState stochează starea care afectează ieșirea componentului; useRef stochează datele necesare pentru logica internă, dar care nu afectează UI.
În practică, dezvoltatorii folosesc adesea useRef pentru a stoca callback-uri, pentru a evita problemele cu închiderile. De exemplu, dacă useEffect se abonează la un eveniment și în interiorul callback-ului este nevoie de state-ul actual — stochează callback-ul în useRef. La fiecare redare actualizează ref.current cu noua funcție, iar efectul va apela întotdeauna callback-ul proaspăt fără reabonare.
| Criteriu | useRef | useState |
|---|---|---|
| Re-rendare | Nu provoacă la modificare | Provoacă la fiecare setState |
| Mutare | Directă: ref.current = value | Prin setter: setState(value) |
| Folosire în JSX | Nu se folosește (fără efect) | Se folosește în ieșirea componentului |
| Exemplu | Timere, referințe DOM, valori anterioare | Date de formular, stare UI, flaguri |
Există un anti-pattern: folosirea useRef pentru a stoca date care sunt necesare în JSX, dar a căror modificare nu ar trebui să provoace re-rendare. Acest lucru duce la desincronizare — UI afișează date vechi, deși ref.current este deja nou. Dacă valoarea este afișată în UI — folosește useState. Dacă este folosită doar în logica internă — useRef.
Combinația useRef + useEffect — un pattern standard pentru urmărirea valorilor anterioare ale props-urilor. Stochează valoarea anterioară în ref, compar-o cu cea curentă în useEffect și ia o decizie pe baza diferenței. Acest lucru este util în special la animații, când trebuie să știi ce valoare a fost înainte de modificare.
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>;
}
Conform React Documentation — Hooks FAQ (2025), acest pattern se numește «previous value pattern». Funcționează deoarece useRef păstrează valoarea între redări, iar useEffect se execută după confirmarea modificărilor. Mai întâi DOM-ul este actualizat cu noul price, apoi useEffect compară cu cel anterior (care este încă în ref) și actualizează ref.current la valoarea curentă.
Cea mai frecventă greșeală — citirea ref.current în faza de redare pentru a calcula JSX-ul. Deoarece modificarea ref.current nu provoacă re-rendare, componentul poate folosi o valoare învechită. Dacă valoarea .current participă la ieșirea UI — folosește useState. Dacă trebuie să sincronizezi ref și state, folosește useEffect pentru a actualiza state-ul din ref.
// ❌ Nu citi ref.current în timpul redării pentru afișare
function BadComponent() {
const valRef = useRef(0);
return <p>{valRef.current}</p>; // NU se va actualiza la mutare
}
// ✅ Folosește state pentru afișare, ref pentru logică
function GoodComponent() {
const [val, setVal] = useState(0);
const valRef = useRef(0);
return <p>{val}</p>;
}
O altă greșeală comună — folosirea useRef ca unic mod de stocare a stării în component, atunci când datele afectează totuși UI. Dezvoltatorii aleg useRef pentru a evita re-rendările «inutile», dar în final obțin un UI care nu se actualizează. Abordarea corectă: folosește useState pentru datele UI și useRef doar pentru valorile auxiliare care nu participă la redare.
Întrebări frecvente
Da, acesta este un pattern comun — previous state pattern. Creează un ref și actualizează-l în useEffect la fiecare modificare a valorii urmărite. În momentul dintre redare și efect, ref.current conține valoarea anterioară care poate fi comparată cu cea curentă. Acest lucru nu necesită re-rendări suplimentare și funcționează cu orice tip de date.
React atribuie ref.current valoarea nodului DOM doar după ce elementul este redat și adăugat în DOM-ul real. În timpul primei redări, componentul nu este încă montat, deci ref.current este egal cu valoarea inițială (null). Accesul la DOM prin ref.current este posibil doar în useEffect sau în handler-ele de evenimente care sunt apelate după montare.
createRef creează un nou obiect ref la fiecare redare — trebuie folosit doar în componentele de clasă. useRef creează ref-ul o dată și returnează același obiect la toate redările ulterioare. În componentele funcționale folosește exclusiv useRef; createRef va duce la pierderea valorii la re-rendare, deoarece obiectul va fi recreat.
Da, obiectul ref poate fi transmis ca un prop obișnuit: <Child inputRef={inputRef} />. Componentul copil îl folosește prin inputRef.current. Totuși, pentru a transmite ref direct la elementul DOM al componentului copil, folosește forwardRef — un HOC care permite trecerea ref-ului prin props. Fără forwardRef, ref-ul nu va fi legat automat la elementul DOM din interiorul componentului copil.
Legă ref-ul de element, apoi în useEffect citește ref.current.getBoundingClientRect() sau ref.current.offsetWidth / offsetHeight. Pentru urmărirea reactivă a modificărilor de dimensiune, folosește ResizeObserver în interiorul useEffect: creează un observer, abonează-te la modificări și actualizează state-ul cu noile dimensiuni. Nu uita să dezactivezi observer-ul în cleanup.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și