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-demoimport { 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 einestry-Blocks – das ist die einzige zuverlässige Methode, unbehandelte Ablehnungen beiasync-Funktionen zu vermeiden. finallystellt sicher, dasssetLadeVorgang(false)IMMER aufgerufen wird – ein sehr häufiger Bug ohnefinally: 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, weilfetch()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 lokaletry/catch-Blöcke.