Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Unhandled Promise Rejection lösen in React Native

Unhandled Promise Rejection lösen

~9 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

"Possible Unhandled Promise Rejection" ist eine der häufigsten Warnungen in React-Native-Apps – sie erscheint, wenn ein Promise mit einem Fehler fehlschlägt ("rejected"), aber KEIN .catch() oder try/catch diesen Fehler auffängt.

1. Beschreibung

JEDE async-Funktion gibt implizit ein Promise zurück, und jeder await-Aufruf kann fehlschlagen (Netzwerkfehler, ungültige JSON-Antwort, abgelehnte Berechtigung). Bleibt der Fehler unbehandelt, protokolliert React Native eine Warnung – im schlimmsten Fall bleibt die App in einem unerwarteten Zustand hängen (z.B. ein Ladekreis, der nie verschwindet).

2. Kurzes Beispiel

// FALSCH: kein Catch, Fehler verschwindet unbemerkt
async function laden() {
  const antwort = await fetch(url); // wirft bei Netzwerkfehler
}

// RICHTIG:
async function laden() {
  try {
    const antwort = await fetch(url);
  } catch (fehler) {
    console.error(fehler);
  }
}

3. Komplettes Projekt: Robuste Datenladung

npx create-expo-app unhandled-rejection-demo
cd unhandled-rejection-demo
App.js
import { useState, useEffect } from 'react';
import { View, Text, Button, ActivityIndicator, StyleSheet } from 'react-native';

async function ladeZitat(schlaegtFehl) {
  const antwort = await fetch(
    schlaegtFehl ? 'https://ungueltige-adresse.example/nichts' : 'https://api.quotable.io/random'
  );
  if (!antwort.ok) {
    throw new Error(`Server antwortete mit Status ${antwort.status}`);
  }
  return antwort.json();
}

export default function App() {
  const [zitat, setZitat] = useState(null);
  const [ladeVorgang, setLadeVorgang] = useState(false);
  const [fehlermeldung, setFehlermeldung] = useState(null);

  async function neuLaden(schlaegtFehl = false) {
    setLadeVorgang(true);
    setFehlermeldung(null);
    // try/catch fängt SOWOHL Netzwerkfehler ALS AUCH das manuelle throw oben ab -
    // ohne dieses try/catch würde jeder Fehlerfall zu einer unbehandelten Ablehnung
    try {
      const daten = await ladeZitat(schlaegtFehl);
      setZitat(daten.content);
    } catch (fehler) {
      console.error('Zitat konnte nicht geladen werden:', fehler.message);
      setFehlermeldung('Zitat konnte nicht geladen werden. Bitte erneut versuchen.');
    } finally {
      // finally läuft IMMER, egal ob Erfolg oder Fehler - Ladezustand endet garantiert
      setLadeVorgang(false);
    }
  }

  useEffect(() => {
    neuLaden();
  }, []);

  return (
    <View style={styles.container}>
      {ladeVorgang && <ActivityIndicator />}
      {zitat && <Text style={styles.zitat}>"{zitat}"</Text>}
      {fehlermeldung && <Text style={styles.fehler}>{fehlermeldung}</Text>}
      <View style={styles.buttons}>
        <Button title="Neues Zitat" onPress={() => neuLaden(false)} />
        <Button title="Fehler simulieren" onPress={() => neuLaden(true)} color="#dc2626" />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, paddingTop: 100, paddingHorizontal: 24 },
  zitat: { fontSize: 16, fontStyle: 'italic', marginBottom: 20 },
  fehler: { color: '#dc2626', marginBottom: 20 },
  buttons: { gap: 12 },
});

4. Erklärung

  • JEDER await-Aufruf, der fehlschlagen KANN, steht innerhalb eines try-Blocks – das ist die einzige zuverlässige Methode, unbehandelte Ablehnungen bei async-Funktionen zu vermeiden.
  • finally stellt sicher, dass setLadeVorgang(false) IMMER aufgerufen wird – ein sehr häufiger Bug ohne finally: der Ladekreis bleibt bei einem Fehler für immer sichtbar, weil das Zurücksetzen im Erfolgspfad "vergessen" wurde, im Fehlerfall gar nicht erst erreicht wird.
  • Der manuelle throw new Error(...) bei einem NICHT-erfolgreichen HTTP-Status ist nötig, weil fetch() selbst (anders als Axios) bei 4xx/5xx-Antworten NICHT automatisch ablehnt (siehe Kapitel "POST-Request senden").
  • In einer produktiven App würde man zusätzlich einen globalen Fallback registrieren (z.B. über ErrorUtils.setGlobalHandler()), der WIRKLICH übersehene Fehler zumindest zentral protokolliert – als letztes Sicherheitsnetz, nicht als Ersatz für lokale try/catch-Blöcke.

5. Ausgaben

Ausgabe
Beim Start erscheint kurz ein Ladekreis, danach ein kursives Zitat in Anführungszeichen. Zwei Buttons darunter: "Neues Zitat" lädt ein neues zufälliges Zitat, "Fehler simulieren" ruft absichtlich eine ungültige URL auf und zeigt stattdessen roten Text "Zitat konnte nicht geladen werden. Bitte erneut versuchen." — in KEINEM Fall bleibt der Ladekreis hängen oder erscheint eine unbehandelte Rejection-Warnung im Terminal.