useRef Hook
Lerne den useRef Hook kennen - für DOM-Zugriff und persistente Werte ohne Re-Render. Praktische Beispiele und Best Practices.
useRef Hook
Der useRef-Hook gibt dir zwei Superkraefte: direkten Zugriff auf DOM-Elemente und die Moeglichkeit, Werte zu speichern, die keinen Re-Render ausloesen. Er ist das perfekte Werkzeug fuer Situationen, in denen useState zu viel des Guten waere.
Was ist useRef?
useRef erstellt ein Objekt mit einer current-Eigenschaft, die zwischen Renders bestehen bleibt:
import { useRef } from 'react';
function MyComponent() {
const myRef = useRef(initialValue);
// Wert lesen
console.log(myRef.current);
// Wert schreiben
myRef.current = 'neuer Wert';
}
DOM-Elemente referenzieren
Der haeufigste Anwendungsfall: auf DOM-Elemente zugreifen:
function FocusInput() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus(); // Direkt auf das DOM-Element zugreifen
}
return (
<div>
<input ref={inputRef} placeholder="Ich bekomme den Fokus..." />
<button onClick={handleClick}>Input fokussieren</button>
</div>
);
}
Wie es funktioniert
1. useRef(null) erstellt { current: null }
2. React setzt ref={inputRef} → inputRef.current = <input>-Element
3. Du kannst inputRef.current wie ein normales DOM-Element nutzen
Weitere DOM-Beispiele
function ScrollToTop() {
const topRef = useRef(null);
function scrollToTop() {
topRef.current.scrollIntoView({ behavior: 'smooth' });
}
return (
<div>
<div ref={topRef} />
{/* Langer Inhalt */}
<div style={{ height: '200vh' }}>Scroll nach unten...</div>
<button onClick={scrollToTop}>Nach oben scrollen</button>
</div>
);
}
function VideoPlayer() {
const videoRef = useRef(null);
return (
<div>
<video ref={videoRef} src="/video.mp4" />
<div>
<button onClick={() => videoRef.current.play()}>Abspielen</button>
<button onClick={() => videoRef.current.pause()}>Pause</button>
<button onClick={() => { videoRef.current.currentTime = 0; }}>
Zuruecksetzen
</button>
</div>
</div>
);
}
Werte speichern ohne Re-Render
Der zweite wichtige Anwendungsfall: Werte merken, ohne die Komponente neu zu rendern:
function RenderCounter() {
const renderCount = useRef(0);
// Bei jedem Render erhoehen - OHNE Re-Render auszuloesen
renderCount.current += 1;
return <p>Diese Komponente wurde {renderCount.current}x gerendert.</p>;
}
useState vs. useRef
useState | useRef | |
|---|---|---|
| Loest Re-Render aus | Ja | Nein |
| Wert bleibt zwischen Renders | Ja | Ja |
| Verwendung in JSX | Ja | Moeglich, aber nicht reaktiv |
| Typischer Einsatz | UI-State | DOM-Zugriff, Hilfswerte |
Vorherigen Wert speichern
Ein nuetzliches Pattern – den vorherigen State-Wert merken:
function PreviousValue() {
const [count, setCount] = useState(0);
const prevCountRef = useRef(0);
useEffect(() => {
prevCountRef.current = count;
}, [count]);
return (
<div>
<p>Aktuell: {count}</p>
<p>Vorher: {prevCountRef.current}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Timer-IDs speichern
Perfekt fuer Timer und Intervalle:
function Stopwatch() {
const [seconds, setSeconds] = useState(0);
const [isRunning, setIsRunning] = useState(false);
const intervalRef = useRef(null);
function start() {
if (isRunning) return;
setIsRunning(true);
intervalRef.current = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
}
function stop() {
setIsRunning(false);
clearInterval(intervalRef.current);
}
function reset() {
stop();
setSeconds(0);
}
// Cleanup beim Unmount
useEffect(() => {
return () => clearInterval(intervalRef.current);
}, []);
return (
<div>
<p style={{ fontSize: '2rem', fontFamily: 'monospace' }}>
{String(Math.floor(seconds / 60)).padStart(2, '0')}:
{String(seconds % 60).padStart(2, '0')}
</p>
<button onClick={start} disabled={isRunning}>Start</button>
<button onClick={stop} disabled={!isRunning}>Stop</button>
<button onClick={reset}>Reset</button>
</div>
);
}
Praktisches Beispiel: Auto-Resize Textarea
function AutoResizeTextarea() {
const textareaRef = useRef(null);
const [text, setText] = useState('');
function handleChange(e) {
setText(e.target.value);
const textarea = textareaRef.current;
textarea.style.height = 'auto';
textarea.style.height = textarea.scrollHeight + 'px';
}
return (
<textarea
ref={textareaRef}
value={text}
onChange={handleChange}
placeholder="Schreibe etwas... Die Textbox waechst mit!"
style={{
width: '100%',
minHeight: '50px',
padding: '0.5rem',
resize: 'none',
overflow: 'hidden',
borderRadius: '8px',
border: '1px solid #ccc'
}}
/>
);
}
Wann useRef statt useState?
Verwende useRef wenn:
- Du auf ein DOM-Element zugreifen musst
- Du einen Wert speichern willst, der keinen Re-Render ausloesen soll
- Du eine Timer-ID oder Interval-ID speichern musst
- Du den vorherigen Wert eines States brauchst
Verwende useState wenn:
- Der Wert in der UI angezeigt werden soll
- Eine Aenderung einen Re-Render ausloesen soll
Uebungen
- Erstelle ein Formular, das automatisch das erste Eingabefeld fokussiert
- Baue eine Stoppuhr mit Start, Stop, Reset und Rundenzeiten
- Erstelle eine Komponente, die misst, wie lange der User auf der Seite ist
Was kommt als Naechstes?
Du kennst jetzt useRef fuer DOM-Zugriff und persistente Werte. Im naechsten Kapitel lernst du den useContext Hook – damit kannst du Daten ueber mehrere Komponentenebenen hinweg teilen, ohne Props durchzureichen.
Zusammenfassung
useReferstellt eine persistente Referenz, die zwischen Renders bestehen bleibt- Hauptanwendungen: DOM-Zugriff und Werte ohne Re-Render speichern
- Aenderungen an
ref.currentloesen keinen Re-Render aus - Ideal fuer Timer-IDs, vorherige Werte und DOM-Manipulationen
- Verwende
useStatewenn der Wert die UI beeinflusst,useRefwenn nicht
Pro-Tipp: Nutze useRef nicht als Ersatz fuer useState, nur weil du Re-Renders vermeiden willst. Wenn ein Wert in der UI sichtbar sein soll, braucht er useState. Vorzeitige Optimierung macht den Code nur schwerer zu verstehen!