Startseite / Artikel / Wie React Query 500 Zeilen aus der API-Schicht einer React Native-App entfernte

Wie React Query 500 Zeilen aus der API-Schicht einer React Native-App entfernte

Ein Fallstudie aus der Praxis zu React Native, die zeigt, wie der Wechsel von manuellem Datenabruf mit useEffect zu React Query wiederholenden Code beseitigte und das Caching sowie die Handhabung im Offline-Modus verbesserte.

1364 Wörter

Einführung

Vor einiger Zeit stieß eine React Native-Codebasis, die Ihnen vielleicht bekannt vorkommt, auf ein bekanntes Problem.

Nahezu jedes Bildschirm, das auf entfernte Daten angewiesen war, folgte demselben Muster:

  • Datenabrufaufrufe innerhalb von useEffect
  • Mehrere separate Ladeindikatoren
  • Custom-Blöcke zur Fehlerbehandlung
  • Eigene Logik für das Ziehen zum Erneuern
  • Manuelle Wiederholungsmechanismen
  • Sonstige Workarounds für das lokale Caching

Funktional war nichts davon kaputt. Doch die Einhaltung dieser Struktur auf Dutzenden von Bildschirmen wurde zu einer echten Wartungsbelastung.

Durch den Wechsel zu React Query (von TanStack) konnte das Team einen großen Teil des wiederholten Netzwerkcodes entfernen und erhielt im Gegenzug eine bessere Caching-Funktion, eine sauberere Ladeverwaltung sowie ein zuverlässigeres Verhalten im Offline-Modus. Die Bibliothek bietet integriertes Abfragescaching, automatische Hintergrund-Neuabfrage sowie netzwerkorientierte Logik, wodurch der Bedarf, diese Zustandsmechanismen selbst zu programmieren, weitgehend entfällt.

Im Folgenden wird der alte manuelle Ansatz im Vergleich zur React Query-Version dargestellt, wobei Muster aus echten Produktions-React Native-Bildschirmen verwendet werden.

Das Problem mit der traditionellen API-Verwaltung

Die Einrichtung eines typischen Bildschirms sah ungefähr so aus:

const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
  fetchData();
}, []);
const fetchData = async () => {
  try {
    setLoading(true);
    const response = await api.getPosts();
    setData(response);
  } catch (err) {
    setError(err);
  } finally {
    setLoading(false);
  }
};

Dieses gleiche Boilerplate tauchte immer wieder im gesamten Anwendungscode auf.

Jeder Bildschirm musste unabhängig verwalten:

  • Ein Ladeflag
  • Ein Fehlerflag
  • Die Handhabung von Wiederholungsversuchen
  • Logik zum Aktualisieren durch Ziehen
  • Eigene Caching-Methode
  • Manuelle Auslöser für erneutes Abrufen
  • Da die App weiter wuchs, wurde dieses wiederkehrende Muster immer schwieriger einheitlich zu halten.

    React Query kommt ins Spiel

    Derselbe Bildschirm, neu geschrieben mit React Query, reduziert sich auf Folgendes:

    const { data, isLoading, error, refetch } = useQuery({
      queryKey: ["posts"],
      queryFn: fetchPosts,
    });
    

    Das ist die gesamte Implementierung.

    React Query kümmert sich automatisch um alles Folgende:

    • Ladeindikatoren
    • Fehlerzustände
    • Deduplizierung identischer laufender Anfragen
    • Abrufen neuer Daten im Hintergrund
    • Verwaltung des Caches
    • Erneute Versuche bei fehlgeschlagenen Anfragen
    • Reaktion auf Wiederherstellung der Netzverbindung

    Der größte Teil dieser Funktionen ist bereits standardmäßig verfügbar und kann über Optionen wie staleTime, gcTime, Konfigurationen für erneute Versuche sowie Einstellungen zum erneuten Abrufen angepasst werden.

    Vergleich #1: Netzwerkanfragen

    Vor React Query

    Stellen Sie sich drei separate Bildschirme vor, die alle dieselben Benutzerprofildaten benötigen.

    Ohne eine gemeinsame Caching-Schicht sendet jeder Bildschirm seine eigene Anfrage:

    Profile Screen → API Call
    Settings Screen → API Call
    Dashboard Screen → API Call
    

    Das Ergebnis: Drei separate Netzwerkaufrufe für dieselben Daten.

    Mit React Query

    Profile Screen → API Call
    Settings Screen → Cached Data
    Dashboard Screen → Cached Data
    

    Dieses Mal das Ergebnis: Nur ein einziger Netzwerkaufruf.

    React Query speichert die Ergebnisse unter einer Abfrage-Identifikation und teilt diese gespeicherten Daten mit allen Komponenten, die danach fragen. Jeder Bildschirm, der später dieselbe Identifikation anfordert, erhält den gespeicherten Wert sofort, während ein Hintergrund-Neuabruf ihn stumm auf dem neuesten Stand hält.

    Ergebnis in der Produktion

    Auf den von Nutzern häufig besuchten Bildschirmen bedeutet das:

    • Weit weniger doppelte Anfragen an die API
    • Kleinerer Lastaufwand für die Backend-Server
    • Schnellere Übergänge zwischen den Bildschirmen

    Vergleich #2: Caching-Effizienz

    Caching ist wohl der Bereich, in dem React Query den größten Nutzen bietet.

    Wenn derselbe Abfragedaten wieder angefordert wird, bevor die gespeicherte Kopie veraltet:

    useQuery({
      queryKey: ["products"],
      queryFn: getProducts,
      staleTime: 300000,
    });
    

    Die Benutzeroberfläche kann die gespeicherten Daten sofort anzeigen, wobei React Query sie optional im Hintergrund leise aktualisiert. Gespeicherte Einträge bleiben bestehen und werden schließlich gemäß Ihren Einstellungen gelöscht.

    Reales Beispiel

    Betrachten Sie den Produktliste-Bildschirm einer E-Commerce-App.

    Ohne Caching bedeutet das Öffnen des Bildschirms:

    Open Products
    ↓
    Network Request
    ↓
    Navigate Back
    ↓
    Open Products Again
    ↓
    Network Request
    

    Mit React Query sieht derselbe Ablauf so aus:

    Open Products
    ↓
    Network Request
    ↓
    Navigate Back
    ↓
    Open Products Again
    ↓
    Instant Cached Data
    

    Der Unterschied ist, dass die App für den Benutzer deutlich schneller wirkt.

    Vergleich #3: Ladezustände

    Bevor React Query eingeführt wurde, bedeutete das Verfolgen des Ladezustands das Handhaben mehrerer Boolescher Werte:

    const [loading, setLoading] = useState(false);
    const [refreshing, setRefreshing] = useState(false);
    const [isRetrying, setIsRetrying] = useState(false);
    

    Danach liefert ein einziger Hook-Aufruf alles, was benötigt wird:

    const {
      isLoading,
      isFetching,
      isRefetching,
    } = useQuery(...)
    

    React Query unterscheidet zwischen dem allerersten Laden und allen nachfolgenden Hintergrundabrufen, wodurch die zugehörige UI-Logik viel einfacher zu verstehen ist.

    Tatsächlicher Vorteil

    Anstatt bei jedem Abruf einen Vollbild-Loader anzuzeigen, kann die App unterscheiden:

    • Erster Laden: Vollbild-Loader
    • Hintergrundaktualisierung: Ein kleiner, unauffälliger Loader
    • Daten sind bereits im Cache: Keine sichtbare Unterbrechung

    Dadurch wirkt die Anwendung für die Nutzer deutlich reaktiver.

    Vergleich #4: Offline-Unterstützung

    Das Verhalten im Offline-Zustand gehört zu den Dingen, die Teams oft unterschätzen.

    Die manuelle Handhabung sieht in der Regel so aus:

    Check Connectivity
    Pause Requests
    Retry Later
    Handle Errors
    Refetch On Reconnect
    

    Das bedeutet, dass spezielle Verbindungslogiken im gesamten Codebase verteilt sind.

    React Query bietet hingegen eine integrierte Verwaltung im Online- und Offline-Modus sowie ein Refetching, das auf Wiederherstellungsereignisse reagiert. In React Native kann man dies mithilfe von onlineManager zusammen mit den Netzwerkstatus-Listenern der Plattform einrichten.

    Zum Beispiel:

    onlineManager.setEventListener(...)
    

    React Query kann auch so konfiguriert werden, dass es im Offline-First-Modus läuft und sein Netzwerkverhalten entsprechend anpasst.

    Echtes Beispiel

    Nehmen wir eine Nachrichten-App als Beispiel.

    Im Laufe eines Tages könnte die Verbindung des Benutzers wie folgt aussehen:

    • Morgen: online
    • Nachmittag: offline
    • Abend: wieder online

    Während dieser gesamten Abfolge bleiben zuvor im Cache gespeicherte Artikel weiterhin lesbar, und sobald die Verbindung wiederhergestellt ist, kann neuer Inhalt automatisch synchronisiert werden.

    Echte Anwendungsfälle

    1. Nachrichten-Apps

    Was das bringt:

    • Gecachte Artikel
    • Automatische Hintergrundaktualisierung
    • Geringerer Gesamt-API-Verkehr
    • Möglichkeit, auch offline weiterzulesen

    2. E-Commerce-Anwendungen

    Vorteile:

    • Gecachte Produktlisten
    • Vorab-Laden von Kategorien
    • Schnellere Navigation zwischen Abschnitten
    • Eine deutlich reibungsloseere Einkaufserfahrung

    React Query unterstützt außerdem das Vorab-Laden von Daten, noch bevor eine Navigation stattfindet, wodurch die wahrgenommenen Wartezeiten verkürzt werden.

    3. Dashboard-Anwendungen

    Vorteile:

    • Widgets, die sich automatisch aktualisieren
    • Ein Cache, der über mehrere Bildschirme geteilt wird
    • Geringerer Netzwerkverkehr
    • Insgesamt viel einfachereres Zustandsmanagement

    Dieses Muster eignet sich besonders gut für Analyse-Dashboards und Admin-Panels.

    Was wir tatsächlich entfernt haben

    Sobald die Migration abgeschlossen war:

    Entfernt

    • Eigene Handhabung des Ladezustands
    • Manueller Wiederholungscode
    • Doppelte Ausgangs-API-Aufrufe
    • Standardcode für Pull-to-Refresh
    • Eigene Cache-Logik
    • Manuelle Verwaltung des Neuladens

    Hinzugefügt

    • Die React Query-Bibliothek selbst
    • Abfrageschlüssel
    • Eine QueryClient-Instanz

    Das Ergebnis: Etwa 500 Zeilen an Code zur API-Verarbeitung waren nicht mehr erforderlich.

    Wann React Query möglicherweise nicht notwendig ist

    Die Verwendung von React Query könnte übertrieben sein, wenn:

    • Ihre Anwendung nur wenige API-Aufrufe macht
    • Die zugrunde liegenden Daten kaum ändern
    • Echtzeit-Caching tatsächlich nicht benötigt wird
    • Das Verhalten im Offline-Modus für Ihren Anwendungsfall nicht wichtig ist

    Doch bei den meisten Produktionsanwendungen überwiegen die Vorteile recht schnell die anfängliche Lernkurve.

    Fazit

    React Query ist mehr als nur eine weitere Möglichkeit, Daten abzurufen.

    Es fungiert als vollständige Lösung für die Verwaltung des Server-Zustands, indem es wiederholenden API-Code eliminiert und gleichzeitig das Caching, das Ladenverhalten, die Netzwerkeffizienz sowie die Nutzung im Offline-Modus verbessert.

    Der größte Vorteil lag hier nicht im reinen Leistungswert.

    Sonderlich die Verringerung der Komplexität.

    Genau diese Kombination machte den Umstieg lohnenswert.