useRef — je React hook, který vytváří mutovatelný ref objekt s vlastností .current, který je zachován mezi rendery komponenty. Na rozdíl od useState, změna .current nezpůsobuje opětovné vykreslení, což činí useRef ideálním pro ukládání DOM referencí, timerů a jakýchkoli hodnot, které musí přežít rendery bez překreslování UI. Podle React Documentation (2025) je ref objekt vytvořen jednou za dobu života komponenty a nemění se mezi rendery, což zaručuje stabilitu reference.
Hlavní body
useRef — je hook přidaný v React 16.8, který vrací mutovatelný ref objekt s jedinou vlastností .current. Počáteční hodnota je přiřazena .current při připojení (mount) komponenty. Hlavní rozdíl oproti běžné proměnné — ref objekt přežije opětovné vykreslení: při opětovném vykreslení React ref znovu nevytváří, ale vrací stejný objekt.
Vnitřní implementace useRef používá stejný mechanismus jako useState a useEffect — propojený seznam hooků na fiber uzlu. Nicméně, na rozdíl od useState, React nesleduje změny ref objektu, neřadí aktualizace do fronty a neplánuje opětovné vykreslení. To činí useRef extrémně lehkým hookem, který neovlivňuje výkon ani při častých změnách.
Podle React Team — Hooks FAQ (2025) je useRef v podstatě „krabička“, která ukládá hodnotu. Syntaktický cukr: const ref = useRef(initialValue) je ekvivalentní const ref = { current: initialValue } s tím rozdílem, že React zaručuje, že ref objekt bude při každém renderu stejný. Žádná magie — prostě stabilní reference spravovaná Reactem.
import { useRef } from 'react';
function Component() {
const countRef = useRef(0);
// countRef.current = 0 zpočátku
// countRef.current = 5 po mutaci
// Nedochází k opětovnému vykreslení!
}
Nejčastější scénář použití useRef — získání přímého přístupu k DOM elementu. React přiřadí elementRef.current referenci na DOM uzel po připojení komponenty. To je nezbytné pro fokusování inputu, měření rozměrů elementu, integraci s animačními knihovnami a knihovnami, které nepoužívají React renderování.
React automaticky spravuje ref reference na DOM: při připojení přiřadí skutečný DOM uzel, při odpojení jej resetuje (nastaví null). To zaručuje, že v .current je vždy aktuální hodnota, a zabraňuje únikům paměti přes „visící“ reference na odstraněné elementy. Není vyžadováno ruční čištění.
function AutoFocusInput() {
const inputRef = useRef(null);
useEffect(() => {
// Zaostřit input po připojení komponenty
inputRef.current?.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
Podle React — Refs and DOM documentation (2025) nepoužívej ref pro deklarativní operace — otevírání/zavírání modálů, správu viditelnosti. Pro tyto účely existují state a props. Refs jsou určeny pro imperativní operace, které nelze vyjádřit deklarativně: fokus, výběr textu, integrace s knihovnami třetích stran.
Druhý nejdůležitější scénář — ukládání libovolných hodnot, které musí být zachovány mezi rendery, ale jejich změna by neměla způsobit opětovné vykreslení. Typické příklady: identifikátory timerů (setInterval/setTimeout), příznaky pro zrušení požadavků, předchozí hodnoty props pro porovnání a jakákoli data, která neovlivňují výstup UI.
To je obzvláště užitečné v useEffect: useRef ukládá identifikátor timeru a cleanup jej čistí. Pokud je timerId uložen v useState, každé volání setTimerId by způsobilo zbytečné opětovné vykreslení, které není potřeba ani pro logiku, ani pro UI. useRef řeší tento problém bez režie a bez zbytečného překreslování.
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></>;
}
Hlavní dilema — volba mezi useRef a useState — je vyřešeno jednou otázkou: „Je při změně hodnoty potřeba opětovné vykreslení?“. Pokud ano — useState. Pokud ne — useRef. useState ukládá stav, který ovlivňuje výstup komponenty; useRef ukládá data potřebná pro interní logiku, ale neovlivňující UI.
V praxi vývojáři často používají useRef k ukládání callbacků, aby se vyhnuli problémům s uzávěry. Například, pokud useEffect odebírá událost a uvnitř callbacku je potřeba aktuální state — ulož callback do useRef. Při každém renderu aktualizuj ref.current novou funkcí a efekt bude vždy volat čerstvý callback bez opětovného přihlášení.
| Kritérium | useRef | useState |
|---|---|---|
| Opětovné vykreslení | Nezpůsobuje při změně | Způsobuje při každém setState |
| Mutace | Přímá: ref.current = value | Přes setter: setState(value) |
| Použití v JSX | Nepoužívá se (žádný efekt) | Používá se ve výstupu komponenty |
| Příklad | Timery, DOM reference, předchozí hodnoty | Data formuláře, UI stav, příznaky |
Existuje anti-vzor: použití useRef k ukládání dat potřebných v JSX, ale jejichž změna by neměla způsobit opětovné vykreslení. To vede k desynchronizaci — UI zobrazuje stará data, i když je ref.current již nový. Pokud je hodnota zobrazována v UI — použij useState. Pokud je používána pouze uvnitř logiky — useRef.
Kombinace useRef + useEffect — standardní vzor pro sledování předchozích hodnot props. Ulož předchozí hodnotu do ref, porovnej s aktuální v useEffect a rozhodni se na základě rozdílu. To je obzvláště užitečné u animací, když potřebuješ vědět, jaká hodnota byla před změnou.
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>;
}
Podle React Documentation — Hooks FAQ (2025) se tento vzor nazývá „previous value pattern“. Funguje, protože useRef uchovává hodnotu mezi rendery a useEffect se spouští po potvrzení změn. Nejprve je DOM aktualizován novou price, poté useEffect porovná s předchozí (která je stále v ref) a aktualizuje ref.current na aktuální hodnotu.
Nejčastější chyba — čtení ref.current ve fázi renderování pro výpočet JSX. Protože změna ref.current nezpůsobuje opětovné vykreslení, komponenta může používat zastaralou hodnotu. Pokud se hodnota .current účastní výstupu UI — použij useState. Pokud potřebuješ synchronizovat ref a state, použij useEffect k aktualizaci state z ref.
// ❌ Nečti ref.current během renderování pro zobrazení
function BadComponent() {
const valRef = useRef(0);
return <p>{valRef.current}</p>; // NEaktualizuje se při mutaci
}
// ✅ Použij state pro zobrazení, ref pro logiku
function GoodComponent() {
const [val, setVal] = useState(0);
const valRef = useRef(0);
return <p>{val}</p>;
}
Další častá chyba — použití useRef jako jediného způsobu ukládání stavu v komponentě, když data přesto ovlivňují UI. Vývojáři volí useRef, aby se vyhnuli „zbytečnému“ opětovnému vykreslení, ale nakonec získají UI, které se neaktualizuje. Správný přístup: použij useState pro UI data a useRef pouze pro pomocné hodnoty, které se neúčastní renderování.
Často kladené otázky
Ano, toto je běžný vzor — previous state pattern. Vytvoř ref a aktualizuj ho v useEffect při každé změně sledované hodnoty. V okamžiku mezi renderem a efektem ref.current obsahuje předchozí hodnotu, kterou lze porovnat s aktuální. Nevyžaduje to další opětovná vykreslení a funguje s libovolnými datovými typy.
React přiřadí ref.current hodnotu DOM uzlu až poté, co je element vykreslen a přidán do skutečného DOM. Během prvního renderu komponenta ještě není připojena, proto je ref.current roven počáteční hodnotě (null). Přístup k DOM přes ref.current je možný pouze v useEffect nebo v obslužných rutinách událostí, které jsou volány po připojení.
createRef vytváří nový ref objekt při každém renderu — měl by být používán pouze v třídových komponentách. useRef vytváří ref jednou a vrací stejný objekt při všech následujících renderováních. Ve funkcionálních komponentách používej výhradně useRef; createRef povede ke ztrátě hodnoty při opětovném vykreslení, protože objekt bude znovu vytvořen.
Ano, ref objekt lze předat jako běžný prop: <Child inputRef={inputRef} />. Dceřiná komponenta jej používá přes inputRef.current. Nicméně pro přímé předání ref na DOM element dceřiné komponenty použij forwardRef — HOC, který umožňuje předání ref přes props. Bez forwardRef se ref automaticky nepřipojí k DOM elementu uvnitř dceřiné komponenty.
Připoj ref k elementu, poté v useEffect čti ref.current.getBoundingClientRect() nebo ref.current.offsetWidth / offsetHeight. Pro reaktivní sledování změn velikosti použij ResizeObserver uvnitř useEffect: vytvoř observer, přihlas se ke změnám a aktualizuj state novými rozměry. Nezapomeň observer vypnout v cleanup.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také