useRef — egy React hook, amely egy mutálható ref objektumot hoz létre .current tulajdonsággal, amely megőrződik a komponens renderelései között. A useState-től eltérően a .current megváltoztatása nem okoz újrarenderelést, ami a useRef-et ideálissá teszi DOM-referenciák, időzítők és olyan értékek tárolására, amelyeknek túl kell élniük a renderelést anélkül, hogy újrarajzolnák a UI-t. A React Documentation (2025) szerint a ref objektum egyszer jön létre a komponens élettartama alatt, és nem változik a renderelések között, garantálva a referencia stabilitását.
Főbb pontok
useRef — egy hook, amelyet a React 16.8-ban adtak hozzá, és egy mutálható ref objektumot ad vissza egyetlen .current tulajdonsággal. A kezdeti érték a komponens mountolásakor kerül a .current-be. A fő különbség egy szokásos változóhoz képest — a ref objektum túléli az újrarendereléseket: újrarendereléskor a React nem hozza létre újra a ref-et, hanem ugyanazt az objektumot adja vissza.
A useRef belső implementációja ugyanazt a mechanizmust használja, mint a useState és a useEffect — a hook-ok láncolt listáját a fiber csomóponton. Azonban a useState-től eltérően a React nem követi nyomon a ref objektum változásait, nem sorolja be a frissítéseket, és nem ütemezi az újrarenderelést. Ez teszi a useRef-et rendkívül könnyű hookká, amely még gyakori változtatások mellett sem befolyásolja a teljesítményt.
A React Team — Hooks FAQ (2025) szerint a useRef lényegében egy „doboz”, amely egy értéket tárol. Szintaktikus cukor: const ref = useRef(initialValue) egyenértékű a const ref = { current: initialValue }-val azzal a különbséggel, hogy a React garantálja, hogy a ref objektum minden rendereléskor ugyanaz lesz. Semmi varázslat — csak egy stabil referencia, amelyet a React kezel.
import { useRef } from 'react';
function Component() {
const countRef = useRef(0);
// countRef.current = 0 kezdetben
// countRef.current = 5 mutáció után
// Nem történik újrarenderelés!
}
A useRef leggyakoribb használati esete — közvetlen hozzáférés a DOM-elemhez. A React a komponens mountolása után az elementRef.current-et a DOM-csomópontra mutató referenciává teszi. Ez szükséges az input fókuszálásához, az elem méreteinek méréséhez, animációs könyvtárakkal és olyan könyvtárakkal való integrációhoz, amelyek nem használnak React-renderelést.
A React automatikusan kezeli a ref-referenciákat a DOM-hoz: mountoláskor hozzárendeli a tényleges DOM-csomópontot, unmountoláskor nullázza (null-ra állítja). Ez garantálja, hogy a .current mindig naprakész értéket tartalmaz, és megakadályozza a memóriaszivárgást a törölt elemekre mutató „lógó” referenciákon keresztül. Nincs szükség kézi tisztításra.
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
// Bemenet fókuszálása a komponens mountolása után
inputRef.current?.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
A React — Refs and DOM documentation (2025) szerint ne használd a ref-et deklaratív műveletekhez — modálok nyitásához/zárásához, láthatóság kezeléséhez. Ezekre a célokra state és props áll rendelkezésre. A ref-ek imperatív műveletekre valók, amelyek nem fejezhetők ki deklaratívan: fókusz, szövegkijelölés, harmadik féltől származó könyvtárakkal való integráció.
A második legfontosabb eset — tetszőleges értékek tárolása, amelyeknek meg kell maradniuk a renderelések között, de változtatásuk nem okozhat újrarenderelést. Tipikus példák: időzítők azonosítói (setInterval/setTimeout), flag-ek kérések megszakításához, előző prop-értékek összehasonlításhoz és bármilyen adat, amely nem befolyásolja a UI kimenetét.
Ez különösen hasznos a useEffect-ben: a useRef tárolja az időzítő azonosítóját, a cleanup pedig törli. Ha a timerId-t useState-ben tárolnánk, minden setTimerId hívás szükségtelen újrarenderelést okozna, amely sem a logikához, sem a UI-hoz nem kell. A useRef megoldja ezt a problémát overhead nélkül és szükségtelen újrarajzolások nélkül.
function Timer() {
const intervalRef = useRef(null);
const start = () => {
intervalRef.current = setInterval(() => {
console.log('tik');
}, 1000);
};
const stop = () => {
clearInterval(intervalRef.current);
};
useEffect(() => stop, []);
return <><button onClick={start}>Start</button><button onClick={stop}>Stop</button></>;
}
A fő dilemma — a választás useRef és useState között — egy kérdéssel megoldható: „Szükséges-e újrarenderelés az érték változásakor?”. Ha igen — useState. Ha nem — useRef. A useState a komponens kimenetét befolyásoló állapotot tárolja; a useRef a belső logikához szükséges adatokat tárolja, amelyek nem befolyásolják a UI-t.
A gyakorlatban a fejlesztők gyakran használják a useRef-et callback-ek tárolására, hogy elkerüljék a closure-ökkel kapcsolatos problémákat. Például, ha a useEffect feliratkozik egy eseményre, és a callback-en belül szükség van a naprakész state-re — tárold a callback-et useRef-ben. Minden rendereléskor frissítsd a ref.current-et az új függvénnyel, és az effekt mindig a friss callback-et hívja meg anélkül, hogy újra feliratkozna.
| Kritérium | useRef | useState |
|---|---|---|
| Újrarenderelés | Nem okoz változtatáskor | Minden setState-kor okoz |
| Mutáció | Közvetlen: ref.current = value | Setteren keresztül: setState(value) |
| Használat JSX-ben | Nem használatos (nincs hatása) | Használatos a komponens kimenetében |
| Példa | Időzítők, DOM-referenciák, előző értékek | Űrlapadatok, UI-állapot, flag-ek |
Létezik egy anti-pattern: a useRef használata olyan adatok tárolására, amelyekre a JSX-ben van szükség, de változtatásuk nem okozhat újrarenderelést. Ez deszinkronizációhoz vezet — a UI régi adatokat mutat, miközben a ref.current már új. Ha az érték megjelenik a UI-ban — használd a useState-et. Ha csak a logikán belül használatos — useRef.
A useRef + useEffect kombináció — egy szabványos minta a prop-ok előző értékeinek nyomon követésére. Tárold az előző értéket ref-ben, hasonlítsd össze a jelenlegivel a useEffect-ben, és hozz döntést a különbség alapján. Ez különösen hasznos animációknál, amikor tudnod kell, hogy mi volt az érték a változtatás előtt.
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>;
}
A React Documentation — Hooks FAQ (2025) szerint ezt a mintát „previous value pattern”-nek hívják. Azért működik, mert a useRef megtartja az értéket a renderelések között, a useEffect pedig a változtatások jóváhagyása után fut le. Először a DOM frissül az új price-szal, majd a useEffect összehasonlítja az előzővel (ami még a ref-ben van), és frissíti a ref.current-et a jelenlegi értékre.
A leggyakoribb hiba — a ref.current olvasása a render fázisban a JSX kiszámításához. Mivel a ref.current változtatása nem okoz újrarenderelést, a komponens elavult értéket használhat. Ha a .current értéke részt vesz a UI kimenetében — használj useState-et. Ha szinkronizálni kell a ref-et és a state-et, használj useEffect-et a state ref-ből történő frissítéséhez.
// ❌ Ne olvasd a ref.current-et renderelés közben megjelenítéshez
function BadComponent() {
const valRef = useRef(0);
return <p>{valRef.current}</p>; // NEM frissül mutációkor
}
// ✅ Használj state-et a megjelenítéshez, ref-et a logikához
function GoodComponent() {
const [val, setVal] = useState(0);
const valRef = useRef(0);
return <p>{val}</p>;
}
Egy másik gyakori hiba — a useRef használata az állapot tárolásának egyetlen módjaként a komponensben, amikor az adatok mégis befolyásolják a UI-t. A fejlesztők a useRef-et választják, hogy elkerüljék a „szükségtelen” újrarendereléseket, de végül egy nem frissülő UI-t kapnak. A helyes megközelítés: használj useState-et a UI-adatokhoz és useRef-et csak a segédértékekhez, amelyek nem vesznek részt a renderelésben.
Gyakran ismételt kérdések
Igen, ez egy elterjedt minta — previous state pattern. Hozz létre egy ref-et, és frissítsd a useEffect-ben a követett érték minden változásakor. A render és az effekt közötti pillanatban a ref.current tartalmazza az előző értéket, amely összehasonlítható a jelenlegivel. Ez nem igényel további újrarendereléseket, és bármilyen adattípussal működik.
A React csak azután rendeli hozzá a ref.current-hez a DOM-csomópont értékét, miután az elem ki lett renderelve és hozzá lett adva a valódi DOM-hoz. Az első renderelés során a komponens még nincs mountolva, ezért a ref.current egyenlő a kezdeti értékkel (null). A DOM-hoz való hozzáférés ref.current-en keresztül csak a useEffect-ben vagy a mountolás után meghívott eseménykezelőkben lehetséges.
A createRef minden rendereléskor új ref objektumot hoz létre — csak osztálykomponensekben használandó. A useRef egyszer hozza létre a ref-et, és ugyanazt az objektumot adja vissza minden következő rendereléskor. Funkcionális komponensekben kizárólag useRef-et használj; a createRef az érték elvesztéséhez vezet újrarendereléskor, mivel az objektum újra létrejön.
Igen, a ref objektum átadható szokásos prop-ként: <Child inputRef={inputRef} />. A gyermek komponens az inputRef.current-en keresztül használja. Azonban a ref közvetlen átadásához a gyermek komponens DOM-eleméhez használd a forwardRef-et — egy HOC-ot, amely lehetővé teszi a ref átadását props-okon keresztül. forwardRef nélkül a ref nem kapcsolódik automatikusan a gyermek komponensen belüli DOM-elemhez.
Csatold a ref-et az elemhez, majd a useEffect-ben olvasd a ref.current.getBoundingClientRect()-et vagy a ref.current.offsetWidth / offsetHeight-t. A méretváltozások reaktív követéséhez használj ResizeObserver-t a useEffect-en belül: hozz létre egy observer-t, iratkozz fel a változásokra, és frissítsd a state-et az új méretekkel. Ne felejtsd el kikapcsolni az observer-t a cleanup-ban.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is