useMemo und useCallback in React verstehen
useMemo und useCallback
~11 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Diese beiden Hooks gehören zusammen: Beide "merken sich" (memoisieren) etwas zwischen Render-Durchläufen, um unnötige, wiederholte Arbeit zu vermeiden. useMemo merkt sich einen berechneten WERT, useCallback merkt sich eine FUNKTION.
Das Grundproblem: jede State-Änderung rendert die ganze Funktion neu
Wichtig zu verstehen: Bei JEDER State-Änderung führt React die komplette Komponentenfunktion erneut aus – nicht nur den Teil, der sich sichtbar ändert. Das bedeutet: JEDE Variable, JEDE Berechnung und JEDE Funktion innerhalb der Komponente wird bei jedem Rendern neu erzeugt. Für einfache Berechnungen (const summe = a + b) ist das völlig unproblematisch – Millionen davon pro Sekunde sind kein Problem. Bei WIRKLICH teuren Berechnungen (große Listen sortieren, komplexe Filterungen) kann das aber spürbar werden.
useMemo(): einen berechneten Wert merken
import { useMemo } from 'react';
const teuersterWert = useMemo(() => {
console.log('Teuerste Berechnung läuft...');
return produkte.reduce((max, p) => (p.price > max ? p.price : max), 0);
}, [produkte]);useMemo(berechnung, [abhaengigkeiten]) führt berechnung nur dann erneut aus, wenn sich einer der Werte im Abhängigkeits-Array seit dem letzten Rendern geändert hat – ändert sich z. B. nur ein UNABHÄNGIGER State-Wert (wie das Suchfeld, falls es nicht in den Abhängigkeiten steht), wird der zwischengespeicherte ("memoisierte") alte Wert einfach wiederverwendet, ohne die Berechnung erneut auszuführen.
App.jsx erweitern: den teuersten Preis anzeigen
Erweitern Sie src/App.jsx um eine mit useMemo berechnete Statistik:
import { useEffect, useMemo, useRef, useState } from 'react';
import ProductCard from './components/ProductCard';
const SAMPLE_PRODUCTS = [
{ sku: 'schuhe-01', name: 'Wanderschuhe', price: 89.99, imageUrl: 'https://picsum.photos/seed/1/300' },
{ sku: 'rucksack-01', name: 'Trekking-Rucksack', price: 59.5, imageUrl: 'https://picsum.photos/seed/2/300' },
{ sku: 'jacke-01', name: 'Regenjacke', price: 74.0, imageUrl: 'https://picsum.photos/seed/3/300' },
];
function App() {
const [query, setQuery] = useState('');
const searchInputRef = useRef(null);
useEffect(() => {
document.title = `Produktkatalog (${SAMPLE_PRODUCTS.length} Produkte)`;
searchInputRef.current.focus();
}, []);
const gefiltert = SAMPLE_PRODUCTS.filter((produkt) =>
produkt.name.toLowerCase().includes(query.toLowerCase())
);
const teuerstesProdukt = useMemo(() => {
console.log('Berechne teuerstes Produkt neu...');
return gefiltert.reduce(
(max, p) => (p.price > (max?.price ?? 0) ? p : max),
null
);
}, [gefiltert]);
return (
<div className="app">
<h1>Produktkatalog</h1>
<input
ref={searchInputRef}
type="text"
placeholder="Produkt suchen..."
value={query}
onChange={(event) => setQuery(event.target.value)}
/>
{teuerstesProdukt && (
<p>Teuerstes Produkt: {teuerstesProdukt.name} ({teuerstesProdukt.price.toFixed(2)} €)</p>
)}
<div className="product-grid">
{gefiltert.map((produkt) => (
<ProductCard
key={produkt.sku}
name={produkt.name}
price={produkt.price}
imageUrl={produkt.imageUrl}
onSelect={() => alert(produkt.name + ' angeklickt')}
/>
))}
</div>
</div>
);
}
export default App;max?.price ?? 0 nutzt "Optional Chaining" (?., gibt undefined statt eines Fehlers zurück, wenn max null ist) und den "Nullish-Coalescing-Operator" (??, liefert den rechten Wert nur bei null/undefined, anders als ||, das auch bei 0 einspringen würde).
useCallback(): eine Funktion merken
useCallback funktioniert genauso wie useMemo, merkt sich aber statt eines Wertes eine FUNKTION selbst – genauer: dieselbe Funktions-REFERENZ über mehrere Render-Durchläufe hinweg, solange sich die Abhängigkeiten nicht ändern.
import { useCallback } from 'react';
const handleProductSelect = useCallback((produkt) => {
console.log('Ausgewählt:', produkt.name);
}, []); // keine Abhängigkeiten = immer dieselbe FunktionsreferenzOhne useCallback erzeugt JEDES Rendern eine BRANDNEUE Funktion – auch wenn ihr Code identisch aussieht, ist es aus JavaScript-Sicht ein neues Objekt im Speicher (fn1 === fn2 wäre false). Das ist meistens egal – wird die Funktion aber an eine mit React.memo optimierte Kind-Komponente übergeben (dazu mehr im Performance-Kapitel des React-für-Profis-Tutorials), verhindert eine "neue" Funktionsreferenz bei jedem Rendern genau die Optimierung, die React.memo eigentlich bringen sollte.
Achtung: Wichtige Faustregel für Einsteiger: Setzen Sie useMemo/useCallback NICHT überall vorsorglich ein. Sie haben selbst einen kleinen Overhead (React muss sich die Abhängigkeiten merken und vergleichen), der bei einfachen Berechnungen/Funktionen mehr kostet, als er einspart. Nutzen Sie sie gezielt: bei WIRKLICH teuren Berechnungen, oder wenn Sie ein konkretes, messbares Performance-Problem haben – nicht "auf Verdacht".