Unnötige Re-Renders visuell finden, ohne den Profiler aufzuzeichnen
Bevor du den Profiler-Tab öffnest und eine Aufzeichnung startest, lassen sich unnötige Re-Renders oft schon mit einem einzigen Klick sichtbar machen. Die React-DevTools-Option Highlight updates when components render färbt jede Komponente ein, sobald ihre Render-Funktion läuft, live im Browser während du klickst, tippst und navigierst.
Inhaltsverzeichnis
- 1. Warum Re-Renders im Alltag unsichtbar bleiben
- 2. Die Option in den React DevTools aktivieren
- 3. Die farbigen Rahmen und Blitze richtig lesen
- 4. Ein konkretes Beispiel für einen unnötigen Re-Render
- 5. Typische Ursachen für unnötige Re-Renders
- 6. Die Ursache mit React.memo, useCallback und useMemo beheben
- 7. Wann der Profiler-Tab die bessere Wahl ist
- 8. Component Highlighting in den täglichen Workflow einbauen
- 9. Grenzen und typische Fallstricke der Methode
- 10. Zusammenfassung
- 11. FAQ
1. Warum Re-Renders im Alltag unsichtbar bleiben
React rendert Komponenten aus gutem Grund sehr häufig neu: Jede State-Änderung, jede neue Prop und jeder Context-Wechsel kann eine Render-Funktion erneut ausführen. Das ist in den meisten Fällen völlig unproblematisch, weil React den virtuellen DOM abgleicht und nur die tatsächlich veränderten Stellen im echten DOM aktualisiert. Das Problem ist nicht der Re-Render selbst, sondern dass er im normalen Browser-Fenster unsichtbar bleibt. Ein Nutzer sieht nur, dass die Seite reagiert, nicht wie oft und wie viele Komponenten dabei unnötig neu berechnet wurden.
Genau diese Unsichtbarkeit macht Performance-Probleme in React-Anwendungen so schwer zu greifen. Ein Formular mit dreißig Eingabefeldern kann bei jedem Tastendruck unbemerkt die komplette Seitenleiste, den Header und eine teure Diagrammkomponente mit rendern, ohne dass sich optisch etwas ändert. Die React DevTools schließen genau diese Lücke: Statt Render-Zyklen aus Logs oder Profiler-Diagrammen zu rekonstruieren, machen sie sie als farbige Rahmen direkt im laufenden Browser-Fenster sichtbar, in Echtzeit und ohne eine einzige Zeile zusätzlichen Code.
2. Die Option in den React DevTools aktivieren
Die Aktivierung dauert wenige Sekunden. Öffne die Browser-DevTools, wechsle zum Tab Components, das kommt mit der React-DevTools-Erweiterung für Chrome, Firefox oder Edge automatisch dazu, und klicke dort auf das Zahnrad-Symbol für die Einstellungen. Im General-Tab findet sich die Checkbox Highlight updates when components render. Sobald sie aktiv ist, zeichnet React DevTools bei jedem Commit, also jedem tatsächlich ausgeführten Render-Durchlauf, einen kurz aufblitzenden farbigen Rahmen um die betroffene Komponente im Seitenbaum.
Kein Build-Schritt, kein Import, keine Instrumentierung im eigenen Code ist dafür nötig, die Option lebt komplett in der Browser-Erweiterung. Das funktioniert identisch in der eigenständigen React-DevTools-App für Native- oder Electron-Kontexte. Relevant ist die Funktion ausschließlich während der Entwicklung: In einem produktiven Build ohne installierte Erweiterung sieht der Endnutzer davon nichts, und die Option hat keinerlei Einfluss auf die eigentliche Bundle-Größe oder Laufzeitperformance der Anwendung.
3. Die farbigen Rahmen und Blitze richtig lesen
Jeder Re-Render einer Komponente erzeugt einen kurzen, farbig umrandeten Blitz um deren gerenderten Bereich im Browser. Die Farbe kodiert dabei grob die Render-Häufigkeit relativ zu anderen Commits: Ein bläuliches Aufblitzen steht für seltene Aktualisierungen, ein Grünton für häufigere, während intensivere Gelb- und Rottöne signalisieren, dass eine Komponente ungewöhnlich oft in kurzer Zeit neu rendert. Diese Farbskala ist kein exaktes Messinstrument, sondern eine schnelle visuelle Heuristik, um Ausreißer im Seitenbaum sofort ins Auge fallen zu lassen.
Eine wichtige Nuance dabei: Das Highlighting zeigt an, dass die Render-Funktion einer Komponente ausgeführt wurde, nicht zwingend, dass sich am Bildschirm etwas sichtbar verändert hat. React kann eine Komponente rendern und dabei exakt dasselbe virtuelle DOM wie zuvor erzeugen, sodass am echten DOM nichts passiert, obwohl die Render-Funktion vollständig durchgelaufen ist und CPU-Zeit gekostet hat. Wer nur auf sichtbare Änderungen achtet, übersieht genau diese Fälle, bei denen unnötige Arbeit passiert, ohne dass sich am Bildschirm irgendetwas bewegt.
4. Ein konkretes Beispiel für einen unnötigen Re-Render
Stell dir eine Seite mit einem Zähler-Button im Header und einer darunter liegenden ExpensiveList vor, die eine größere Produktliste rendert und dabei gar keine Daten vom Zähler benötigt. Beide Komponenten haben denselben Elternteil, der den Zählerstand in einem useState hält. Ohne weitere Maßnahmen führt jeder Klick auf den Button dazu, dass die Elternkomponente neu rendert und dabei standardmäßig auch alle Kindkomponenten erneut aufruft, selbst jene, die von dem geänderten State überhaupt nicht abhängen.
Mit aktivem Highlighting ist das Ergebnis sofort sichtbar: Ein Klick auf den Zähler-Button lässt nicht nur die Zahl im Header, sondern auch den kompletten Rahmen der ExpensiveList kurz aufblitzen, obwohl sich deren Inhalt inhaltlich nicht ändert. Genau dieses Muster, ein isolierter State-Wechsel löst eine kaskadierende Re-Render-Welle über völlig unbeteiligte Unterbäume aus, ist die häufigste Kategorie unnötiger Re-Renders in React-Anwendungen und mit bloßem Auge sonst kaum zu erkennen.
function Dashboard() {
const [count, setCount] = useState(0);
return (
<div>
<Header count={count} onIncrement={() => setCount((c) => c + 1)} />
{/* ExpensiveList haengt nicht von "count" ab, rendert aber trotzdem mit */}
<ExpensiveList items={PRODUCTS} />
</div>
);
}
function ExpensiveList({ items }) {
console.log("ExpensiveList rendert");
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
5. Typische Ursachen für unnötige Re-Renders
Die häufigste Ursache ist strukturell und hat wenig mit dem konkreten Beispiel zu tun: In React rendert eine Elternkomponente standardmäßig alle Kindkomponenten mit, sobald sich ihr eigener State ändert, unabhängig davon, ob die Kinder betroffene Props überhaupt konsumieren. Verschärft wird das durch inline erzeugte Objekte, Arrays und Funktionen als Props, etwa ein Handler wie onClick={() => doSomething()} direkt im JSX. Bei jedem Render entsteht eine neue Funktionsreferenz, selbst wenn ihr Inhalt identisch bleibt, was jeden nachgelagerten Identitätsvergleich zunichtemacht.
Eine zweite häufige Quelle ist der React Context: Wird der an einen Provider übergebene value als neues Objekt-Literal bei jedem Render der Elternkomponente erzeugt, etwa value={{ user, theme }} direkt im JSX, dann rendern sämtliche Consumer dieses Contexts bei jeder Änderung mit, selbst wenn nur eines der beiden Felder sich tatsächlich geändert hat. Gerade globale Contexts für Theme, Auth oder Sprache betreffen dann potenziell die gesamte Anwendung und erzeugen genau die Art von kaskadierendem Highlighting, die im Seitenbaum sofort auffällt.
// Problematisch: neues Objekt bei jedem Render
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState("light");
// { user, theme } ist bei jedem Render eine neue Objekt-Referenz
return (
<AppContext.Provider value={{ user, theme }}>
{children}
</AppContext.Provider>
);
}
6. Die Ursache mit React.memo, useCallback und useMemo beheben
Der Fix setzt an zwei Stellen gleichzeitig an, denn beide brauchen sich gegenseitig: Die Kindkomponente wird mit React.memo umschlossen, damit sie einen Re-Render überspringt, solange sich ihre Props laut oberflächlichem Vergleich nicht geändert haben. Das allein reicht aber nicht, wenn die Elternkomponente bei jedem Durchlauf trotzdem neue Prop-Referenzen erzeugt. Deshalb müssen Callback-Funktionen mit useCallback und Objekt- oder Array-Literale mit useMemo stabilisiert werden, jeweils mit einem Dependency-Array, das nur bei echten inhaltlichen Änderungen eine neue Referenz erzeugt.
Nach dem Fix zeigt genau dieselbe Highlighting-Technik den Erfolg: Ein Klick auf den Zähler-Button lässt nur noch den Header aufblitzen, die ExpensiveList bleibt unbeleuchtet, weil React.memo den Vergleich der stabil gehaltenen Props erkennt und den Render-Aufruf überspringt. Wichtig ist dabei, React.memo nicht reflexartig auf jede Komponente zu legen: Der Vergleich selbst kostet auch Zeit, und bei kleinen, günstig zu rendernden Komponenten kann die Memoisierung mehr Overhead erzeugen, als sie einspart. Highlighting hilft auch hier, den tatsächlichen Nutzen vor und nach der Änderung objektiv zu vergleichen.
const ExpensiveList = memo(function ExpensiveList({ items }) {
console.log("ExpensiveList rendert");
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
});
function Dashboard() {
const [count, setCount] = useState(0);
// useCallback haelt die Funktionsreferenz stabil
const handleIncrement = useCallback(() => setCount((c) => c + 1), []);
// items kommt hier bereits als stabile Referenz von auszen (z.B. Konstante)
return (
<div>
<Header count={count} onIncrement={handleIncrement} />
<ExpensiveList items={PRODUCTS} />
</div>
);
}
7. Wann der Profiler-Tab die bessere Wahl ist
Component Highlighting beantwortet zuverlässig die Frage, ob eine Komponente überhaupt neu rendert, aber nicht, wie teuer dieser Render tatsächlich war. Genau dafür ist der Profiler-Tab gedacht: Eine Aufzeichnung liefert ein Flame-Chart mit Render-Dauer pro Komponente in Millisekunden, die Anzahl der Commits während der Aufzeichnung und, bei aktivierter Option, sogar Hinweise darauf, welche Props oder welcher State-Wechsel den jeweiligen Render ausgelöst hat. Das macht ihn zum richtigen Werkzeug, sobald es um belastbare Zahlen statt um eine grobe Ersteinschätzung geht.
In der Praxis bewährt sich eine klare Reihenfolge: Highlighting zuerst, um verdächtige Kandidaten im Seitenbaum überhaupt zu finden, danach der Profiler, um zu quantifizieren, ob sich der Aufwand einer Optimierung lohnt. Eine Komponente, die zwar sichtbar aufblitzt, deren Render aber laut Profiler nur 0,1 Millisekunden dauert, ist selten die Ursache spürbarer Ruckler. Wer stattdessen direkt jede aufblitzende Komponente mit React.memo umwickelt, verbringt schnell mehr Zeit mit Memoisierung als mit dem eigentlichen Performance-Gewinn.
8. Component Highlighting in den täglichen Workflow einbauen
Am meisten Nutzen bringt die Option, wenn sie fester Bestandteil der Entwicklungsroutine wird, statt nur bei akuten Performance-Beschwerden aktiviert zu werden. Besonders lohnenswert ist ein kurzer Check direkt nach dem Hinzufügen von neuem State, einem neuen Context oder einer neu verdrahteten Prop-Kette: Ein Blick auf den Seitenbaum während einer typischen Interaktion zeigt sofort, ob die Änderung unerwartet weite Kreise zieht. Manche Teams etablieren das als festen Punkt im Self-Review vor jedem Pull Request mit UI-relevanten Änderungen.
Ergänzend lohnt sich für tiefergehende Fälle ein kleiner selbstgebauter Debug-Hook, der Render-Zähler und veränderte Props direkt in der Konsole protokolliert, wenn das visuelle Blitzen allein nicht reicht, um die Ursache zu isolieren. Für automatisiertes, dauerhaftes Monitoring über die manuelle Beobachtung hinaus bieten sich ergänzend Bibliotheken wie why-did-you-render oder React Scan an, die Ursachen direkt benennen statt nur zu visualisieren. Component Highlighting bleibt dabei aber der schnellste erste Schritt, weil er ganz ohne zusätzliche Abhängigkeit sofort verfügbar ist.
function useRenderCount(label) {
const countRef = useRef(0);
countRef.current += 1;
useEffect(() => {
console.log(`${label} rendert zum ${countRef.current}. Mal`);
});
return countRef.current;
}
function ExpensiveList({ items }) {
useRenderCount("ExpensiveList");
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
9. Grenzen und typische Fallstricke der Methode
Im Strict Mode von React 18 und 19 führt der Entwicklungs-Build absichtlich jeden Render und ausgewählte Effekte doppelt aus, um versteckte Nebenwirkungen früh sichtbar zu machen. Das führt dazu, dass Component Highlighting im Strict Mode häufig doppelt so oft aufblitzt wie im produktiven Verhalten, was neu einsteigende Entwickler leicht mit einem echten Performance-Problem verwechseln. Ein Blick in die Produktions-Build-Simulation oder das bewusste Ausblenden der ersten Doppelung schafft hier Klarheit, bevor man einer Phantom-Ursache hinterherjagt.
Die zweite Grenze ist subtiler: Fehlendes Aufblitzen ist kein Beweis für gute Performance, denn teure Berechnungen können auch außerhalb des eigentlichen Render-Zyklus liegen, etwa in einem schweren useEffect, einer teuren Event-Handler-Logik oder einer synchronen Berechnung, die unabhängig vom Component-Tree läuft. Component Highlighting beantwortet ausschließlich die Frage nach der Render-Häufigkeit, nicht nach der Gesamtkosten der Interaktion. Wer sich ausschließlich darauf verlässt, übersieht ganze Klassen von Performance-Problemen, die erst im Profiler oder in echten Performance-Traces sichtbar werden.
| Methode | Zeigt | Aufwand | Bester Einsatzzeitpunkt |
|---|---|---|---|
| Component Highlighting | Dass eine Komponente rendert, farbig live im Browser | Ein Klick, keine Aufzeichnung nötig | Erste, schnelle Sichtung während der Entwicklung |
| Profiler-Tab | Render-Dauer, Commit-Anzahl, Auslöser pro Commit | Aufzeichnung starten und stoppen | Belastbare Zahlen vor einer gezielten Optimierung |
| why-did-you-render | Exakte Ursache: welche Prop oder welcher State-Wert sich änderte | Bibliothek einbinden und konfigurieren | Tiefenanalyse hartnäckiger Einzelfälle |
| Eigener useRenderCount-Hook | Render-Anzahl und Zeitpunkt in der Konsole | Wenige Zeilen eigener Code | Gezieltes Debugging einer bestimmten Komponente |
Mironsoft
React-Architektur, Performance und Magento-Frontend-Integration
React-Frontends, die schnell bleiben statt mit jedem Feature langsamer zu werden?
Wir prüfen bestehende React-Anwendungen auf unnötige Re-Renders, aufgeblähte Bundles und fragile State-Verwaltung und bauen daraus ein Frontend, das performant bleibt und sich sauber an Magento oder andere Backends anbindet.
Performance-Audit
Re-Renders, Bundle-Größe und Ladezeiten systematisch messen und beheben.
State-Architektur
Context, Zustand und Server State sauber trennen statt alles in einen Topf zu werfen.
Magento-Integration
GraphQL- oder REST-Anbindung an Magento robust und typsicher aufbauen.
10. Zusammenfassung
React DevTools Highlighting: Das Wichtigste auf einen Blick
Aktivierung
Components-Tab in den React DevTools öffnen, Zahnrad, Highlight updates when components render anhaken.
Farbcode
Blau bis Rot zeigt die relative Render-Häufigkeit, kein exaktes Messinstrument, sondern eine schnelle Heuristik.
Häufigste Ursache
Inline erzeugte Objekte, Arrays und Funktionen als Props sowie unstabile Context-Values.
Fix
React.memo an der Kindkomponente, kombiniert mit useCallback und useMemo an der Quelle der Props.