Error Boundary Retry und Reset Patterns fuer resiliente React UIs
AI generated
{ }
React · Fehlerbehandlung · Resilienz
Error Boundary Retry und Reset Patterns
fuer resiliente React UIs, die sich selbst wieder erholen

Eine Error Boundary, die nach einem Fehler dauerhaft eine graue Wand zeigt, ist nur die halbe Loesung. Mit resetKeys, Retry Buttons und einem sauberen Reset Mechanismus wird aus dem Fallback ein echter Wiederherstellungspfad statt einer Sackgasse.

15 Min. Lesezeit react-error-boundary resetKeys Retry UX

1. Warum eine Error Boundary allein nicht reicht

Eine klassische Error Boundary in React faengt Rendering-Fehler in ihrem Kindbaum ab und zeigt statt eines weissen Bildschirms eine Fallback-UI. Das ist der Ausgangspunkt, aber in einer produktiven Anwendung reicht das nicht aus: Sobald der Fehler einmal aufgetreten ist, bleibt die Boundary dauerhaft im Fehlerzustand haengen, weil componentDidCatch den internen State einmalig setzt und React die Komponente danach nicht mehr automatisch neu rendert. Der Nutzer sieht eine Fehlermeldung und hat ohne einen kompletten Seiten-Reload keine Moeglichkeit, wieder in einen funktionierenden Zustand zu gelangen.

Resiliente UIs brauchen deshalb zwei zusaetzliche Faehigkeiten: einen expliziten Weg, den Fehlerzustand zurueckzusetzen, und einen Mechanismus, der bei bestimmten Aenderungen automatisch zuruecksetzt, etwa wenn sich die Route oder eine zentrale Prop aendert. Beide Anforderungen lassen sich mit reinem React umsetzen, werden aber durch die Bibliothek react-error-boundary von Kent C. Dodds deutlich komfortabler, weil sie das resetKeys Pattern und einen onReset Callback bereits mitbringt, statt dass man sie in jeder Boundary neu erfindet.

2. Das resetKeys Pattern von react-error-boundary

Die Komponente ErrorBoundary aus react-error-boundary akzeptiert eine Prop namens resetKeys: ein Array von Werten, das die Boundary bei jedem Render vergleicht. Aendert sich auch nur einer dieser Werte zwischen zwei Renders, setzt die Boundary ihren internen Fehlerzustand automatisch zurueck und versucht, die Kinder erneut zu rendern, ganz ohne dass der Nutzer aktiv etwas tun muss. Das ist besonders nuetzlich, wenn ein Fehler an einen konkreten Datensatz gebunden ist, etwa eine Produkt ID in einer Detailseite: Navigiert der Nutzer zu einem anderen Produkt, ist der alte Fehler nicht mehr relevant und die Boundary soll ihn nicht mehr anzeigen.

In der Praxis uebergibt man typischerweise die Werte, von denen der gerenderte Inhalt abhaengt, etwa die Produkt ID aus den URL Parametern oder einen Query Key. Wichtig dabei: resetKeys vergleicht die Werte oberflaechlich, sodass primitive Werte wie Strings oder Zahlen zuverlaessig funktionieren, waehrend neu erzeugte Objekte oder Arrays bei jedem Render als veraendert gelten und ungewollte Resets ausloesen koennen. Deshalb sollten resetKeys moeglichst aus stabilen, primitiven Identifikatoren bestehen und nicht aus Objekten, die bei jedem Render neu instanziiert werden.


import { ErrorBoundary } from 'react-error-boundary';
import { useParams } from 'react-router-dom';

function ProductErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert" className="rounded-lg border border-red-200 bg-red-50 p-4">
      <p className="font-semibold text-red-800">Produkt konnte nicht geladen werden</p>
      <p className="text-sm text-red-700">{error.message}</p>
      <button
        onClick={resetErrorBoundary}
        className="mt-2 rounded bg-red-600 px-3 py-1.5 text-sm text-white"
      >
        Erneut versuchen
      </button>
    </div>
  );
}

function ProductDetailPage() {
  const { productId } = useParams();

  return (
    <ErrorBoundary
      FallbackComponent={ProductErrorFallback}
      resetKeys={[productId]}
    >
      <ProductDetail productId={productId} />
    </ErrorBoundary>
  );
}

3. Retry Button fuer manuelles Zuruecksetzen

react-error-boundary reicht der Fallback-Komponente eine Funktion namens resetErrorBoundary durch. Ruft der Nutzer sie ueber einen Button auf, setzt die Boundary ihren internen Fehlerzustand zurueck und versucht, die Kinder erneut zu rendern, genau wie bei resetKeys, nur manuell ausgeloest statt automatisch. Das ist die richtige Wahl fuer Fehler, deren Ursache nicht an eine erkennbare Prop gebunden ist, etwa ein voruebergehender Netzwerkfehler beim Laden eines Widgets, bei dem der Nutzer selbst entscheiden soll, wann ein neuer Versuch sinnvoll ist.

Ein reiner Reset des UI-Zustands loest allerdings nicht automatisch die eigentliche Ursache: Wenn die Komponente beim ersten Render aus einem fehlerhaften Cache oder einer fehlgeschlagenen Anfrage einen Fehler geworfen hat, wuerde ein simpler Remount denselben Fehler sofort reproduzieren. Deshalb kombiniert man den Retry Button meist mit einer expliziten Refetch-Funktion und einem Retry-Zaehler, der nach einigen erfolglosen Versuchen die Fallback-UI aendert, etwa von 'Erneut versuchen' zu 'Bitte spaeter erneut versuchen', um dem Nutzer keine Endlosschleife anzubieten.


import { useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

function RetryFallback({ error, resetErrorBoundary }) {
  const [attempts, setAttempts] = useState(0);
  const maxAttempts = 3;

  const handleRetry = () => {
    setAttempts((a) => a + 1);
    resetErrorBoundary();
  };

  return (
    <div role="alert" className="rounded-lg border p-4">
      <p>{error.message}</p>
      {attempts < maxAttempts ? (
        <button onClick={handleRetry}>Erneut versuchen</button>
      ) : (
        <p className="text-sm text-gray-500">
          Bitte lade die Seite in ein paar Minuten neu.
        </p>
      )}
    </div>
  );
}

function Widget({ refetch }) {
  return (
    <ErrorBoundary
      FallbackComponent={RetryFallback}
      onReset={() => refetch()}
    >
      <DataDrivenWidget />
    </ErrorBoundary>
  );
}

4. Eine eigene Error Boundary Klasse ohne Bibliothek

Error Boundaries lassen sich in React bis heute nur als Klassenkomponente implementieren, weil sie die Lifecycle-Methoden static getDerivedStateFromError und componentDidCatch benoetigen, fuer die es keine Hook-Entsprechung gibt. getDerivedStateFromError wird synchron beim Rendern aufgerufen und liefert den neuen State, der die Fallback-UI aktiviert, waehrend componentDidCatch danach fuer Nebeneffekte wie Logging zustaendig ist. Wer keine zusaetzliche Abhaengigkeit einfuehren will, kann diese beiden Methoden mit wenig Code selbst implementieren.

Fuer den Reset ohne Bibliothek hat sich der Key-Remount-Trick etabliert: Man haelt einen Zaehler im Elternzustand und uebergibt ihn als key an die Boundary beziehungsweise an ihre Kinder. Aendert sich der key, entfernt React die gesamte Instanz und erzeugt sie neu, wodurch auch der interne Fehlerzustand der Boundary garantiert verschwindet, ganz ohne eine eigene resetError-Methode auf der Klasse implementieren zu muessen. Der Trick ist simpel, aber wirksam, weil er sich auf Reacts eingebautes Reconciliation-Verhalten stuetzt statt auf eigene State-Logik.


import { Component } from 'react';

class SimpleErrorBoundary extends Component {
  state = { hasError: false, error: null };

  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  componentDidCatch(error, info) {
    console.error('Boundary caught:', error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback(this.state.error);
    }
    return this.props.children;
  }
}

function Parent() {
  const [resetCount, setResetCount] = useState(0);

  return (
    <SimpleErrorBoundary
      key={resetCount}
      fallback={(error) => (
        <button onClick={() => setResetCount((c) => c + 1)}>
          Neu laden ({error.message})
        </button>
      )}
    >
      <RiskyChild />
    </SimpleErrorBoundary>
  );
}

5. Grenzen: Was Error Boundaries nicht abfangen

Error Boundaries fangen ausschliesslich Fehler ab, die waehrend des Renderns, in Lifecycle-Methoden oder in Konstruktoren von Komponenten unterhalb der Boundary geworfen werden. Nicht abgefangen werden Fehler in Event Handlern wie onClick, Fehler in asynchronem Code wie setTimeout-Callbacks oder Promise-Ketten, Fehler beim serverseitigen Rendering und Fehler, die innerhalb der Boundary selbst auftreten. Ein try/catch in einem fetch-Callback, das nur die Konsole beschreibt, wird also niemals die Fallback-UI der umgebenden Boundary auslösen, egal wie die Boundary konfiguriert ist.

Um solche asynchronen Fehler dennoch ueber dieselbe Boundary sichtbar zu machen, nutzt man den 'throw in render' Trick: Man haelt den Fehler in einem State und wirft ihn beim naechsten Render explizit, sodass React ihn wie einen regulaeren Render-Fehler behandelt und die naechste Error Boundary greift. react-error-boundary bietet dafuer den Hook useErrorHandler beziehungsweise in neueren Versionen ein aehnliches Pattern, das genau diese Bruecke zwischen imperativem async Code und deklarativer Fehlerbehandlung schlaegt.


import { useState, useCallback } from 'react';

function useThrowAsyncError() {
  const [, setError] = useState();

  return useCallback((error) => {
    setError(() => {
      throw error;
    });
  }, []);
}

function AsyncWidget() {
  const throwAsyncError = useThrowAsyncError();

  useEffect(() => {
    fetchData().catch((err) => throwAsyncError(err));
  }, [throwAsyncError]);

  return <DataView />;
}

6. Granularitaet: Wo Boundaries platzieren

Eine einzige Error Boundary rund um die gesamte App ist schnell eingebaut, hat aber einen entscheidenden Nachteil: Ein Fehler in einem einzelnen, unwichtigen Widget wie einer Produktempfehlung reisst dann die komplette Seite mit in den Fehlerzustand, obwohl der Rest der Anwendung problemlos funktionieren wuerde. Am anderen Ende des Spektrums steht eine Boundary um jede einzelne Komponente, was zwar maximale Isolation bietet, aber massiv Boilerplate erzeugt und dazu fuehrt, dass zusammengehoerige UI-Bereiche unabhaengig voneinander in Fehlerzustaende fallen koennen, was fuer den Nutzer verwirrend wirkt.

In der Praxis bewaehrt sich eine zweistufige Strategie: eine grobe, applikationsweite Boundary am Wurzelknoten als letzte Sicherheitsnetz-Instanz, kombiniert mit gezielten Boundaries um in sich geschlossene Feature-Widgets wie einen Warenkorb, eine Kommentarsektion oder ein Empfehlungs-Karussell. Jede dieser inneren Boundaries bekommt eigene resetKeys, die zum Datenkontext des jeweiligen Widgets passen, sodass ein Fehler im Empfehlungs-Widget niemals den Checkout-Bereich derselben Seite lahmlegt.

7. Fallback UI und UX Ueberlegungen

Die Fallback-UI sollte dem Nutzer klar kommunizieren, ob es sich um ein voruebergehendes Problem handelt, das ein erneuter Versuch loesen kann, oder um einen dauerhaften Fehler, bei dem ein Retry Button nur Frustration erzeugt. Technische Details wie Stacktraces gehoeren in Produktion nicht in die sichtbare UI, sondern in ein separates Logging-System, waehrend die sichtbare Meldung verstaendlich und handlungsorientiert bleibt, etwa 'Dieser Bereich konnte nicht geladen werden' statt einer rohen Fehlermeldung aus der JavaScript Engine.

Layout-technisch sollte die Fallback-UI moeglichst dieselbe Groesse einnehmen wie der eigentliche Inhalt, damit umliegende Elemente nicht springen, wenn der Fehler auftritt oder behoben wird. Fuer Barrierefreiheit ist ein role='alert' auf dem Fallback-Container wichtig, damit Screenreader die Fehlermeldung automatisch ankuendigen, und bei kritischen Fehlern kann zusaetzlich der Fokus explizit auf die Fehlermeldung gesetzt werden, damit Tastaturnutzer sie nicht uebersehen.

8. Fehler an Monitoring wie Sentry melden

componentDidCatch liefert neben dem Fehlerobjekt auch ein info-Objekt mit componentStack, das genau zeigt, in welchem Komponentenbaum der Fehler aufgetreten ist, was fuer die Fehlersuche oft wertvoller ist als der reine JavaScript-Stacktrace. Diese Information sollte an ein Monitoring-System wie Sentry weitergereicht werden, idealerweise angereichert um Kontext wie die aktuellen resetKeys, die Retry-Anzahl und relevante IDs, damit sich Haeufungen bestimmter Fehler bestimmten Datensaetzen zuordnen lassen.

react-error-boundary bietet dafuer die Prop onError auf der ErrorBoundary-Komponente, die zentral an einer Stelle im Code das Reporting uebernimmt, statt es in jeder einzelnen Boundary zu wiederholen. Wichtig ist dabei, Wiederholungen zu deduplizieren: Wenn ein Nutzer denselben Fehler durch mehrfaches Klicken auf Retry mehrfach ausloest, sollte das Monitoring nicht jedes Mal ein separates, gleichwertiges Ereignis erzeugen, sondern die Retry-Anzahl als zusaetzliches Feld am urspruenglichen Ereignis fuehren.


import * as Sentry from '@sentry/react';
import { ErrorBoundary } from 'react-error-boundary';

function App() {
  return (
    <ErrorBoundary
      FallbackComponent={AppFallback}
      onError={(error, info) => {
        Sentry.captureException(error, {
          contexts: { react: { componentStack: info.componentStack } },
          tags: { boundary: 'app-root' },
        });
      }}
    >
      <Router />
    </ErrorBoundary>
  );
}

9. Praxischeckliste und Vergleich der Ansaetze

Fuer kleine, isolierte Anwendungen ohne externe Abhaengigkeiten kann eine selbst geschriebene Boundary mit Key-Remount ausreichen, weil sie ohne zusaetzliches Paket auskommt und der Code vollstaendig unter eigener Kontrolle bleibt. Sobald aber mehrere Boundaries mit unterschiedlichen resetKeys, Retry-Zaehlern und zentralem Error-Reporting gebraucht werden, zahlt sich react-error-boundary aus, weil es diese Muster bereits robust und gut getestet implementiert, statt dass jedes Team sie erneut nachbaut.

Die folgende Tabelle fasst zusammen, welcher Ansatz zu welchem Anwendungsfall passt. Als Faustregel gilt: automatischer Reset ueber resetKeys fuer datenabhaengige Fehler, manueller Retry Button fuer netzwerkbedingte Fehler, und eine Kombination aus beidem fuer Widgets, die sowohl von externen Daten als auch von instabilen Verbindungen abhaengen.

Ansatz Automatischer Reset Aufwand Einsatzgebiet
Eigene Klasse ohne Reset Nein Niedrig Prototypen, einmalige Fallbacks
Eigene Klasse mit Key-Remount Nein, manuell ueber Key Mittel Kleine Apps ohne Extra-Paket
react-error-boundary ohne resetKeys Nein, nur Retry Button Niedrig Netzwerk-abhaengige Widgets
react-error-boundary mit resetKeys Ja, bei Prop-Aenderung Niedrig Detailseiten mit wechselnder ID
react-error-boundary mit onReset und Retry-Zaehler Ja, plus begrenzte manuelle Versuche Mittel Kritische Widgets mit Monitoring

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

Error Boundary Retry Patterns: Das Wichtigste auf einen Blick

resetKeys

Array von Werten, bei dessen Aenderung die Boundary automatisch zuruecksetzt, ideal fuer datenabhaengige Fehler wie wechselnde IDs.

Retry Button

resetErrorBoundary manuell aufrufen, kombiniert mit Refetch und einem Versuchszaehler gegen Endlosschleifen.

Key-Remount

Eigene Boundary ohne Bibliothek per key-Aenderung am Elternzustand zuruecksetzen, nutzt Reacts Reconciliation.

Monitoring

componentStack aus componentDidCatch an Sentry oder aehnliche Tools senden, Retry-Anzahl als Kontext mitfuehren.

11. FAQ: Error Boundary Retry Patterns: Das Wichtigste auf einen Blick

1Was ist der Unterschied zwischen resetKeys und einem manuellen Retry Button?
resetKeys loest den Reset automatisch aus, sobald sich einer der uebergebenen Werte aendert, zum Beispiel eine Produkt ID nach einer Navigation. Ein Retry Button dagegen wird explizit vom Nutzer geklickt und ruft die von react-error-boundary bereitgestellte Funktion resetErrorBoundary auf. Beide Mechanismen lassen sich gleichzeitig auf derselben Boundary verwenden.
2Kann ich Error Boundaries als Function Component mit Hooks schreiben?
Nein, React bietet aktuell keine Hook-Entsprechung fuer getDerivedStateFromError und componentDidCatch, deshalb muessen Error Boundaries als Klassenkomponente implementiert werden. Bibliotheken wie react-error-boundary kapseln diese Klasse intern, sodass man im eigenen Code trotzdem nur mit der deklarativen Komponente und Hooks wie useErrorHandler arbeitet.
3Warum loesen meine resetKeys staendig ungewollte Resets aus?
Meist liegt es daran, dass ein neu erzeugtes Objekt oder Array als resetKey uebergeben wird, das bei jedem Render eine neue Referenz erhaelt, auch wenn der Inhalt identisch bleibt. Die Boundary vergleicht resetKeys oberflaechlich per Referenz, deshalb sollten nur stabile, primitive Werte wie IDs oder Strings als resetKeys verwendet werden.
4Fangen Error Boundaries auch Fehler in Event Handlern ab?
Nein, Error Boundaries fangen ausschliesslich Fehler ab, die waehrend des Renderns oder in Lifecycle-Methoden auftreten. Fehler in onClick oder anderen Event Handlern muessen weiterhin mit try/catch im Handler selbst behandelt werden, oder man wirft sie ueber einen State-Trick in den naechsten Render, damit die Boundary sie erfasst.
5Wie verhindere ich eine Retry-Endlosschleife bei dauerhaften Fehlern?
Ein Versuchszaehler in der Fallback-Komponente, der die Anzahl der Retry-Klicks mitzaehlt, ist der einfachste Schutz. Nach einer festgelegten Anzahl von Versuchen, etwa drei, blendet man den Retry Button aus und zeigt stattdessen einen Hinweis, es spaeter erneut zu versuchen, statt den Nutzer in eine endlose Klickschleife laufen zu lassen.
6Sollte ich eine einzige globale Error Boundary oder viele kleine verwenden?
Am robustesten ist eine Kombination: eine grobe Boundary am Wurzelknoten als letztes Sicherheitsnetz und zusaetzliche, gezielte Boundaries um unabhaengige Feature-Widgets. So bleibt der Rest der Seite funktionsfaehig, wenn nur ein einzelnes Widget einen Fehler wirft, waehrend die globale Boundary katastrophale Faelle abfaengt.
7Wie melde ich Fehler aus einer Error Boundary an Sentry?
react-error-boundary bietet die Prop onError, die bei jedem gefangenen Fehler mit dem Fehlerobjekt und dem componentStack aufgerufen wird. Dort ruft man Sentry.captureException auf und kann zusaetzlichen Kontext wie die aktuelle Retry-Anzahl oder relevante IDs als Tags oder Extra-Daten mitgeben.
8Was ist der Key-Remount-Trick und wann brauche ich ihn?
Beim Key-Remount-Trick uebergibt man der Error Boundary oder ihren Kindern einen key, der sich bei einem gewuenschten Reset aendert, zum Beispiel ein hochgezaehlter Zaehler. React entfernt dann die alte Instanz komplett und erzeugt eine neue, wodurch auch der interne Fehlerzustand verschwindet. Der Trick ist nuetzlich, wenn man ohne react-error-boundary auskommen moechte.
9Muss die Fallback-UI dieselbe Groesse wie der Originalinhalt haben?
Idealerweise ja, damit umliegende Layout-Elemente nicht springen, wenn ein Fehler auftritt oder durch einen Reset behoben wird. Besonders bei Widgets innerhalb eines Grids oder einer Liste sorgt eine passend dimensionierte Fallback-UI fuer ein stabileres, weniger sprunghaftes Nutzererlebnis.
10Erkennt eine Error Boundary auch Fehler beim serverseitigen Rendering?
Nein, Error Boundaries funktionieren nur im Client-seitigen Rendering-Zyklus von React. Fehler waehrend eines Server-Side-Rendering-Durchlaufs, etwa mit renderToPipeableStream, muessen ueber die dafuer vorgesehenen onError und onShellError Callbacks der jeweiligen Server-Rendering-API behandelt werden, nicht ueber eine client-seitige Boundary.