Der useRef-Hook in React: DOM-Zugriff und Werte ohne Re-Render
useRef kann mehr als nur DOM-Elemente ansteuern. Du lernst, wie du damit Eingabefelder fokussierst, Werte über Renderings hinweg speicherst und unnötige Neu-Renderings vermeidest.
Du kennst wahrscheinlich schon useState und useEffect. Doch React hat noch einen kleinen, oft unterschätzten Hook im Gepäck: useRef. Er löst zwei Probleme, an denen State und Props scheitern – der direkte Zugriff auf DOM-Elemente und das Speichern von Werten, die sich ändern dürfen, ohne dass deine Komponente neu rendert. In diesem Beitrag schauen wir uns beide Anwendungsfälle mit lauffähigen Beispielen an.
Was ist useRef eigentlich?
useRef gibt dir ein veränderbares Objekt zurück, das über die gesamte Lebensdauer deiner Komponente stabil bleibt. Dieses Objekt hat genau eine Eigenschaft: current. Du kannst current jederzeit lesen und überschreiben – und das Entscheidende ist: Eine Änderung an current löst kein neues Rendering aus.
Genau das unterscheidet den Hook von useState. Bei setState rendert React die Komponente neu, damit die Oberfläche den neuen Wert widerspiegelt. Ein Ref dagegen ist wie eine Schublade, in die du etwas legst und später wieder herausholst, ohne dass jemand davon erfährt.
import { useRef } from "react";
function Beispiel() {
const ref = useRef(0); // Startwert: 0
console.log(ref.current); // liest den Wert
ref.current = 42; // schreibt einen neuen Wert
return <p>Schau in die Konsole</p>;
}DOM-Elemente direkt ansprechen
Der klassische Einsatz ist der Zugriff auf ein DOM-Element. Normalerweise beschreibt React die Oberfläche deklarativ, aber manchmal brauchst du direkten Zugriff – etwa um ein Eingabefeld zu fokussieren. Dafür hängst du das Ref über das ref-Attribut an ein Element. React setzt dann automatisch current auf den echten DOM-Knoten.
import { useRef } from "react";
function SearchBox() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Suche..." />
<button onClick={handleFocus}>Ins Feld springen</button>
</div>
);
}Ein Klick auf den Button ruft inputRef.current.focus() auf und setzt den Cursor ins Eingabefeld. Wichtig: Beim allerersten Render ist current noch null, weil das Element erst danach im DOM existiert. Greif also nicht direkt beim Rendern darauf zu, sondern in einem Event-Handler oder in useEffect.
Werte speichern ohne Neu-Rendering
Der zweite Anwendungsfall wird oft übersehen: Du kannst mit useRef beliebige Werte über Renderings hinweg behalten. Ein schönes Beispiel ist eine Stoppuhr. Die ID, die setInterval zurückgibt, brauchst du später zum Stoppen – sie soll aber kein Rendering auslösen. Perfekt für ein Ref:
import { useRef, useState } from "react";
function Stopwatch() {
const [seconds, setSeconds] = useState(0);
const intervalRef = useRef(null);
const start = () => {
if (intervalRef.current !== null) return; // läuft schon
intervalRef.current = setInterval(() => {
setSeconds((s) => s + 1);
}, 1000);
};
const stop = () => {
clearInterval(intervalRef.current);
intervalRef.current = null;
};
return (
<div>
<p>{seconds} Sekunden</p>
<button onClick={start}>Start</button>
<button onClick={stop}>Stopp</button>
</div>
);
}Würdest du die Interval-ID in useState speichern, würde jeder Start ein zusätzliches Rendering auslösen – völlig unnötig, denn die ID gehört nicht auf den Bildschirm. Sie ist reine interne Buchhaltung, und genau dafür ist ein Ref gemacht.
Den vorherigen Wert merken
Ein weiterer eleganter Trick: Mit einer Kombination aus useRef und useEffect kannst du dir den vorherigen Wert eines States merken. Da useEffect erst nach dem Rendern läuft, enthält das Ref beim nächsten Durchlauf noch den alten Wert.
import { useRef, useEffect, useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const prevCount = useRef();
useEffect(() => {
prevCount.current = count; // läuft nach dem Render
}, [count]);
return (
<div>
<p>Jetzt: {count}, vorher: {prevCount.current}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}Beim Rendern liest React zuerst prevCount.current (noch der alte Wert) und aktualisiert es erst danach im Effekt. So hast du den direkten Vergleich zwischen altem und neuem Zustand – praktisch für Animationen oder um auf Änderungen zu reagieren.
useRef oder useState – wann was?
Die Faustregel ist einfach: Frag dich, ob der Wert auf dem Bildschirm sichtbar sein soll.
- Nutze
useState, wenn eine Änderung die Oberfläche aktualisieren muss – Zähler, Eingaben, Sichtbarkeit von Elementen. - Nutze
useRef, wenn du einen Wert nur behalten willst, ohne dass ein Rendering nötig ist – Timer-IDs, DOM-Knoten, vorherige Werte oder Flags.
Und noch eine Warnung: Verändere ein Ref niemals mitten im Rendering, um daraus die Ausgabe zu berechnen. Refs sind bewusst „unsichtbar" für React – wenn ihr Wert auf dem Bildschirm erscheinen soll, gehört er in den State.
Fazit
useRef ist ein kleiner Hook mit zwei starken Fähigkeiten: Er verschafft dir direkten Zugriff auf DOM-Elemente und dient als stiller Speicher für Werte, die kein Rendering auslösen sollen. Merk dir die zentrale Frage – „Soll sich die Oberfläche ändern?" – und du weißt sofort, ob du zu useState oder useRef greifst. Probier die Beispiele am besten selbst aus: Bau die Stoppuhr nach oder ergänze deine Formulare um einen Autofokus. So wird der Unterschied zwischen sichtbarem State und interner Referenz schnell zur Selbstverständlichkeit.