REST API Anbindung mit TanStack Query in React Native
AI generated
RN
native
React Native · TanStack Query · REST API
REST API Anbindung mit TanStack Query in React Native
von QueryClient bis Offline-Persistenz mit AsyncStorage

TanStack Query löst in React Native genau die Probleme, an denen plain fetch mit useEffect und useState scheitert: Race Conditions bei schneller Navigation, fehlendes Caching, doppelte Requests und kein automatisches Neuladen beim Zurückkehren aus dem Hintergrund. Mit QueryClient, useQuery, useMutation, NetInfo-Reconnect und einem AsyncStorage-Persister wird die REST-Anbindung robust, gecacht und offlinefähig.

19 Min. Lesezeit QueryClient · useQuery · useMutation · NetInfo · persistQueryClient React Native · Expo · TanStack Query v5

1. Warum fetch, useEffect und useState in React Native an ihre Grenzen stoßen

Der naheliegendste Weg, Daten in einer React-Native-Komponente zu laden, ist ein useEffect, das beim Mounten einen fetch-Aufruf startet, während drei useState-Variablen für Loading, Fehler und Daten sorgen. Für einen Demo-Screen funktioniert das. Sobald eine App mehrere Screens, Tabs und schnelle Navigation hat, zeigt dieses Muster handfeste Lücken, die genau der Grund sind, warum TanStack Query mittlerweile der Standard für Datenzugriffe in React Native ist. Das erste Problem sind Race Conditions: Wechselt ein Nutzer schnell zwischen zwei Listen-Filtern oder Tabs, feuert jeder Wechsel einen neuen Request, aber die Antworten kommen nicht garantiert in derselben Reihenfolge zurück. Ohne Abbruch- oder Versionslogik kann eine ältere Antwort später ankommen als die neuere und den State mit veralteten Daten überschreiben, ohne dass ein Fehler sichtbar wird.

Das zweite Problem ist fehlendes Caching. In React-Native-Navigationsstacks werden Screens beim Zurück-Navigieren oft komplett neu gemountet, wodurch der useEffect erneut feuert und dieselben Daten nochmal über ein mobiles Netz lädt, obwohl sie Sekunden zuvor schon geladen wurden. Das kostet Datenvolumen, Akku und Zeit, gerade auf 4G- oder 3G-Verbindungen. Ein verwandtes Problem sind doppelte In-Flight-Requests: Wenn zwei Komponenten auf demselben Screen dieselbe Ressource brauchen, feuert jede ihren eigenen fetch, statt sich einen laufenden Request zu teilen. Ohne zentrale Cache-Schicht gibt es in reinem React keinen eingebauten Mechanismus, der solche Duplikate erkennt.

Das dritte, in mobilen Apps besonders spürbare Problem: Kehrt eine App aus dem Hintergrund zurück, etwa nachdem ein Nutzer kurz eine andere App geöffnet hat, bleibt der alte State einfach stehen, bis der Nutzer manuell per Pull-to-Refresh neu lädt. Genau diese drei Lücken, Race Conditions, fehlendes Caching und kein automatisches Neuladen bei App-Resume, schließt TanStack Query, indem es Server-State als eigenen Zustand behandelt, getrennt vom lokalen UI-State, inklusive Caching, Deduplizierung und lifecycle-bewusstem Refetching.

2. QueryClient und QueryClientProvider: das Fundament in Expo/React Native

Jede Anwendung, die TanStack Query nutzt, braucht genau eine Instanz von QueryClient, die als zentraler Cache fungiert und über QueryClientProvider an der Wurzel der App zur Verfügung gestellt wird, in Expo typischerweise in App.tsx oder im Root-Layout von Expo Router. Anders als im Web sollten die Default-Optionen für React Native bewusst angepasst werden, weil mobile Netzverbindungen instabiler sind und Datenvolumen teurer ist als bei einer Desktop-Verbindung. Ein längeres staleTime von zum Beispiel einer Minute verhindert, dass jede Rückkehr zu einem Screen sofort einen Refetch auslöst, während eine reduzierte Retry-Anzahl mit exponentiellem Backoff verhindert, dass die App eine instabile Verbindung mit endlosen Wiederholungsversuchen belastet.

Die Installation der benötigten Pakete umfasst neben dem Kernpaket auch die Bibliotheken für NetInfo, AsyncStorage und die Persistenz-Helfer, die in den folgenden Abschnitten gebraucht werden. Alle vier Pakete werden am besten direkt zu Beginn installiert, weil das Setup von QueryClient, focusManager und onlineManager typischerweise in derselben Datei zusammenhängt.


# Core TanStack Query package for React Native / Expo
npm install @tanstack/react-query

# NetInfo: required to wire the onlineManager for refetch-on-reconnect
npm install @react-native-community/netinfo

# AsyncStorage: backing store for the offline persistence layer
npm install @react-native-async-storage/async-storage

# Persist client helpers for rehydrating the cache across app restarts
npm install @tanstack/query-async-storage-persister @tanstack/react-query-persist-client

Das folgende Setup zeigt, wie QueryClient mit mobil-tauglichen Defaults konfiguriert wird, wie focusManager über AppState an den App-Lifecycle angebunden wird und wie onlineManager später mit NetInfo verdrahtet wird, bevor im nächsten Abschnitt useQuery im Detail erklärt wird.


// App.tsx - QueryClient setup tuned for mobile networks
import { AppState, Platform } from 'react-native';
import NetInfo from '@react-native-community/netinfo';
import {
  QueryClient,
  QueryClientProvider,
  focusManager,
  onlineManager,
  useQuery,
} from '@tanstack/react-query';

// Mobile networks are less reliable than desktop connections,
// so retries and staleTime are tuned differently than the library defaults
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60 * 1000, // 1 minute: avoid refetching on every screen focus
      gcTime: 5 * 60 * 1000, // keep unused cache entries for 5 minutes
      retry: 2, // fail fast on mobile instead of hammering a flaky connection
      retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
      refetchOnReconnect: true,
    },
  },
});

// React Native has no window focus events, so TanStack Query needs
// AppState to know when the app returns from background to foreground
function onAppStateChange(status) {
  if (Platform.OS !== 'web') {
    focusManager.setFocused(status === 'active');
  }
}

AppState.addEventListener('change', onAppStateChange);

// React Native has no navigator.onLine, so the onlineManager must be
// wired manually to NetInfo to enable refetchOnReconnect correctly
onlineManager.setEventListener((setOnline) => {
  return NetInfo.addEventListener((state) => {
    setOnline(!!state.isConnected && state.isInternetReachable !== false);
  });
});

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <ProductListScreen />
    </QueryClientProvider>
  );
}

// A typical screen using useQuery instead of fetch + useEffect + useState
function ProductListScreen() {
  const { data, isLoading, isFetching, isError, error, refetch } = useQuery({
    queryKey: ['products', { category: 'sale' }],
    queryFn: async () => {
      const response = await fetch('https://api.example.com/products?category=sale');
      if (!response.ok) {
        throw new Error('Failed to load products');
      }
      return response.json();
    },
  });

  if (isLoading) {
    return <LoadingSpinner />;
  }

  if (isError) {
    return <ErrorView message={error.message} onRetry={refetch} />;
  }

  return <ProductList products={data} isRefreshing={isFetching} />;
}

3. useQuery in der Praxis: Daten laden ohne Boilerplate

Der useQuery-Hook von TanStack Query ersetzt die drei manuellen useState-Variablen aus der Einleitung durch ein einziges Objekt mit klar definierten Feldern. Der erste Parameter, der Query Key, ist ein Array, das die Query eindeutig identifiziert, im Beispiel oben ['products', { category: 'sale' }]. Der zweite Parameter, die Query-Funktion, ist eine simple async Function, die die Daten lädt und im Fehlerfall wirft, statt einen Fehler-State manuell zu setzen. Wichtig für eine gute Nutzerführung in React Native ist der Unterschied zwischen isLoading, das nur beim allerersten Laden ohne Cache-Daten true ist, und isFetching, das auch bei jedem Hintergrund-Refetch true wird. Diese Unterscheidung erlaubt es, beim ersten Laden ein volles Skeleton zu zeigen und bei späteren Refetches nur einen dezenten Spinner am Bildschirmrand.

Ein zentraler Vorteil von TanStack Query gegenüber manuellem fetch ist die automatische Deduplizierung: Nutzen mehrere Komponenten auf demselben Screen denselben Query Key, teilen sie sich einen einzigen laufenden Request und einen gemeinsamen Cache-Eintrag, statt unabhängig voneinander dieselbe Ressource abzufragen. Das löst das Problem doppelter In-Flight-Requests direkt an der Wurzel, ohne dass Entwickler dafür eigene Locking- oder Debounce-Logik schreiben müssen.

Ebenfalls eingebaut ist ein Retry-Mechanismus mit exponentiellem Backoff, der bei kurzzeitigen Netzwerkfehlern automatisch erneut versucht, bevor ein Fehler an die UI durchgereicht wird. Auf Mobilgeräten, die häufig zwischen WLAN und Mobilfunk wechseln, verhindert das, dass ein kurzer Verbindungsabbruch von einer Sekunde sofort zu einer Fehleranzeige führt, obwohl die Verbindung Sekundenbruchteile später wieder stabil ist.

4. useMutation, Query Keys und Invalidation

Während useQuery für lesende Zugriffe zuständig ist, übernimmt useMutation das Schreiben, also POST-, PUT- und DELETE-Aufrufe gegen die REST-API. Nach einer erfolgreichen Mutation ruft man typischerweise queryClient.invalidateQueries mit einem passenden Query Key auf, damit betroffene Listen automatisch neu geladen werden, ohne dass man manuell den lokalen State der Liste anpassen muss. Diese Kombination aus useMutation und Invalidation ist einer der Gründe, warum TanStack Query in React Native so viel Boilerplate gegenüber manuellem State-Management einspart.

Damit Invalidation präzise funktioniert, müssen Query Keys durchdacht strukturiert sein. Ein Array wie ['products', { category: 'sale' }] erlaubt es, gezielt nur diese Kombination zu invalidieren, während ein Aufruf mit nur ['products'] alle Varianten dieser Query-Familie invalidiert, unabhängig vom Filter. Diese hierarchische Struktur der Query Keys ist ein Kernkonzept, das man verstehen muss, um Invalidation weder zu grob, mit unnötigen Refetches, noch zu fein, mit übersehenen veralteten Caches, einzusetzen.

Für eine sofort reagierende Oberfläche eignen sich Optimistic Updates: Statt auf die Server-Antwort zu warten, ändert man den Cache in onMutate bereits vor dem Request, macht in onError die Änderung rückgängig, falls die Mutation scheitert, und stößt in onSettled eine Invalidation an, um den Cache endgültig mit dem Server abzugleichen. Dieses Muster aus Snapshot, optimistischer Änderung, Rollback und finalem Abgleich ist in TanStack Query standardisiert und macht Optimistic Updates in React Native deutlich robuster als handgeschriebene Lösungen.


// useMutation with optimistic update and query invalidation
import { useMutation, useQueryClient } from '@tanstack/react-query';

function useToggleFavorite() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (productId) => {
      const response = await fetch(`https://api.example.com/products/${productId}/favorite`, {
        method: 'POST',
      });
      if (!response.ok) {
        throw new Error('Failed to toggle favorite');
      }
      return response.json();
    },

    // Optimistic update: flip the UI instantly, before the server responds
    onMutate: async (productId) => {
      const queryKey = ['products', { category: 'sale' }];

      // Cancel outgoing refetches so they do not overwrite the optimistic value
      await queryClient.cancelQueries({ queryKey });

      // Snapshot the previous value for rollback on error
      const previousProducts = queryClient.getQueryData(queryKey);

      queryClient.setQueryData(queryKey, (old) =>
        old?.map((product) =>
          product.id === productId
            ? { ...product, isFavorite: !product.isFavorite }
            : product
        )
      );

      return { previousProducts, queryKey };
    },

    // Roll back to the snapshot if the mutation fails
    onError: (error, productId, context) => {
      if (context?.previousProducts) {
        queryClient.setQueryData(context.queryKey, context.previousProducts);
      }
    },

    // Always resync with the server after the mutation settles
    onSettled: (data, error, productId, context) => {
      queryClient.invalidateQueries({ queryKey: context.queryKey });
      queryClient.invalidateQueries({ queryKey: ['product', productId] });
    },
  });
}

5. Background Refetching: Daten aktuell halten

Background Refetching ist einer der Punkte, an denen TanStack Query den größten Unterschied zu einer manuellen Lösung macht, weil es fast unsichtbar im Hintergrund arbeitet. Ein zwischengespeicherter Query gilt bis zum Ablauf von staleTime als frisch, wird danach aber beim nächsten Mounten oder Fokussieren als veraltet markiert und automatisch neu geladen, während die bisherigen Daten weiter angezeigt werden. Wichtig ist der Unterschied zwischen staleTime, das bestimmt, wie lange Daten als frisch gelten, und gcTime, das bestimmt, wie lange ein ungenutzter Cache-Eintrag überhaupt im Speicher bleibt, bevor er entfernt wird.

Auf React Native ist Background Refetching eng an den App-Lifecycle gekoppelt. Da native Apps in einen Hintergrundzustand wechseln können, ohne dass die JavaScript-Umgebung neu startet, registriert das im vorherigen Setup gezeigte focusManager.setFocused, gekoppelt an AppState, jeden Wechsel zwischen active und background. Kehrt die App aus dem Hintergrund zurück, markiert TanStack Query alle veralteten Queries automatisch für einen Refetch, genau die Fähigkeit, die bei plain fetch und useEffect vollständig fehlt und die Nutzer sonst zum manuellen Pull-to-Refresh zwingt.

Zusätzlich lässt sich mit refetchInterval ein Polling-Intervall definieren, etwa für einen Bestellstatus-Screen, der alle 15 Sekunden prüfen soll, ob sich der Status geändert hat, solange der Screen sichtbar ist. Kombiniert mit dem AppState-Listener pausiert dieses Polling automatisch, sobald die App in den Hintergrund wechselt, wodurch keine unnötigen Requests laufen, während der Nutzer die App gar nicht sieht.

6. Refetch-on-Reconnect: NetInfo und der onlineManager

Im Browser verlässt sich TanStack Query standardmäßig auf navigator.onLine und die Events online und offline des Window-Objekts, um zu erkennen, wann eine Verbindung wiederhergestellt wurde. In React Native existiert dieses Browser-API schlicht nicht, weshalb der eingebaute onlineManager ohne zusätzliche Konfiguration in einer nativen App gar nicht funktioniert. An dieser Stelle kommt @react-native-community/netinfo ins Spiel, die Standardbibliothek für Konnektivitätsstatus in React Native, die über native Module den tatsächlichen Netzwerkstatus des Geräts abfragt.

Die Anbindung erfolgt über onlineManager.setEventListener, wie im Setup-Code in Abschnitt 2 gezeigt: NetInfo liefert bei jeder Statusänderung ein Objekt mit isConnected und isInternetReachable. Der Unterschied zwischen beiden ist wichtig, denn ein Gerät kann durchaus mit einem WLAN-Router verbunden sein, isConnected also true, ohne dass dieser Router tatsächlich Internetzugang hat, was isInternetReachable auf false setzt. Eine robuste Implementierung prüft deshalb beide Werte, bevor sie TanStack Query als online meldet.

Sobald der onlineManager korrekt mit NetInfo verdrahtet ist, greift refetchOnReconnect automatisch: Verliert das Gerät die Verbindung und stellt sie Sekunden oder Minuten später wieder her, etwa beim Verlassen eines Aufzugs oder eines U-Bahn-Tunnels, refetcht TanStack Query alle als veraltet markierten Queries selbstständig, ohne dass die Anwendung eigene Logik für Netzwerküberwachung implementieren muss.

7. Offline-Persistenz mit einem AsyncStorage-Persister

Während Background Refetching und Reconnect-Handling regeln, wie der Cache während einer laufenden App-Session aktuell bleibt, löst die Persistenz ein anderes Problem: Was zeigt die App direkt nach einem Kaltstart, bevor irgendeine Netzwerkantwort eingetroffen ist. Ohne Persistenz startet der Cache bei jedem App-Start leer, wodurch selbst ein Nutzer mit hervorragender Datenlage im Vorfeld erst wieder einen Ladezustand sieht. TanStack Query löst das über persistQueryClient in Kombination mit einem Persister, der den Cache in einem persistenten Speicher ablegt und beim nächsten Start wiederherstellt.

Für React Native ist AsyncStorage der naheliegende Speicherort, und die Bibliothek @tanstack/query-async-storage-persister stellt einen fertigen Persister bereit, der intern AsyncStorage.getItem und AsyncStorage.setItem aufruft, um den serialisierten Cache zu lesen und zu schreiben. Alternativ lässt sich ein eigener Persister schreiben, der lediglich die drei Methoden persistClient, restoreClient und removeClient implementieren muss, was in Fällen sinnvoll ist, in denen ein anderer Speicher als AsyncStorage verwendet werden soll, etwa ein verschlüsselter Secure-Storage für sensible Daten.

Wichtige Konfigurationsoptionen sind maxAge, das festlegt, wie alt ein wiederhergestellter Cache maximal sein darf, bevor er verworfen wird, und buster, ein String, der bei jedem App-Update erhöht werden kann, um veraltete Cache-Formate nach einer Schema-Änderung automatisch zu invalidieren. Mit dehydrateOptions lässt sich zudem steuern, welche Queries überhaupt persistiert werden, etwa um Auth-Tokens oder sehr große Listen bewusst auszuschließen.


{
  "persistOptions": {
    "maxAge": 86400000,
    "buster": "app-version-1.4.0",
    "dehydrateOptions": {
      "shouldDehydrateQuery": "query.queryKey[0] !== 'auth' && query.state.status === 'success'"
    }
  },
  "asyncStoragePersisterOptions": {
    "storageKey": "TANSTACK_QUERY_OFFLINE_CACHE",
    "throttleTime": 1000,
    "serialize": "JSON.stringify(client)",
    "deserialize": "JSON.parse(cachedString)"
  }
}

8. useInfiniteQuery: paginierte Listen ohne Offset-Tracking

Für paginierte Listen, etwa einen Produktkatalog oder einen Activity-Feed, der per Endless Scroll in einer FlatList nachgeladen wird, bietet TanStack Query mit useInfiniteQuery einen eigenen Hook, der das manuelle Mitführen von Offset oder Seitenzahl im lokalen State überflüssig macht. Die Query-Funktion erhält einen pageParam, mit dem sie die nächste Seite anfragt, während getNextPageParam aus der Antwort der API liest, ob und welcher Cursor oder welche Seitenzahl für die nächste Anfrage verwendet werden soll.

Die Rückgabe von useInfiniteQuery enthält neben den üblichen Feldern wie isLoading zusätzlich data.pages, ein Array aller bereits geladenen Seiten, sowie fetchNextPage, hasNextPage und isFetchingNextPage. In einer FlatList kombiniert man onEndReached mit einem Aufruf von fetchNextPage, sobald hasNextPage true ist und gerade keine Seite lädt, während ListFooterComponent einen Ladeindikator während des Nachladens zeigt.

Wichtig ist, dass Caching und Invalidation für useInfiniteQuery genauso funktionieren wie für useQuery: Der Query Key identifiziert die gesamte paginierte Liste, und ein invalidateQueries mit diesem Key lädt beim nächsten Zugriff wieder von der ersten Seite an neu, was besonders nach einer Mutation sinnvoll ist, die die Sortierung oder Filterung der Liste verändert haben könnte.


// useInfiniteQuery for a paginated product list rendered in a FlatList
import { useInfiniteQuery } from '@tanstack/react-query';
import { FlatList, ActivityIndicator } from 'react-native';

function usePaginatedProducts() {
  return useInfiniteQuery({
    queryKey: ['products', 'paginated'],
    queryFn: async ({ pageParam = 1 }) => {
      const response = await fetch(`https://api.example.com/products?page=${pageParam}&limit=20`);
      if (!response.ok) {
        throw new Error('Failed to load page');
      }
      return response.json(); // { items: [...], nextPage: number | null }
    },
    getNextPageParam: (lastPage) => lastPage.nextPage ?? undefined,
    initialPageParam: 1,
  });
}

function PaginatedProductList() {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    isLoading,
  } = usePaginatedProducts();

  if (isLoading) {
    return <ActivityIndicator />;
  }

  const products = data?.pages.flatMap((page) => page.items) ?? [];

  return (
    <FlatList
      data={products}
      keyExtractor={(item) => String(item.id)}
      renderItem={({ item }) => <ProductRow product={item} />}
      onEndReachedThreshold={0.4}
      onEndReached={() => {
        if (hasNextPage && !isFetchingNextPage) {
          fetchNextPage();
        }
      }}
      ListFooterComponent={isFetchingNextPage ? <ActivityIndicator /> : null}
    />
  );
}

9. fetch, RTK Query, SWR und TanStack Query im Vergleich

Für die Datenanbindung in React Native stehen neben plain fetch mit useEffect mehrere etablierte Bibliotheken zur Auswahl, die alle einen ähnlichen Zweck verfolgen, sich aber deutlich in Umfang und mobilspezifischer Integration unterscheiden. Die folgende Tabelle stellt TanStack Query den Alternativen Redux Toolkit Query und SWR sowie der manuellen Lösung gegenüber, jeweils entlang der Kriterien, die in den vorherigen Abschnitten behandelt wurden.

Kriterium fetch + useEffect + useState Redux Toolkit Query SWR TanStack Query
Caching & Deduplizierung Keines, jeder Mount lädt neu Ja, über Redux Store integriert Ja, ähnliches Cache-Modell Ja, Query Keys als Cache-Schlüssel
Offline-Persistenz Muss komplett selbst gebaut werden Zusätzlich redux-persist nötig Kein eingebauter RN-Persister persistQueryClient mit AsyncStorage-Persister
Optimistic Updates Manuell, viel Boilerplate Über createAsyncThunk möglich Über mutate() mit optimistic data Standardisiertes onMutate/onError-Pattern
NetInfo/AppState-Integration Keine, komplett selbst verdrahtet Kein eingebauter Mechanismus Eigener Provider nötig, wenig RN-Doku onlineManager/focusManager als offizielle Extension Points
Bundle-Größe / Abhängigkeiten Keine Zusatzabhängigkeit Komplettes Redux Toolkit nötig Sehr klein, minimalistisch Moderat, modular per Plugin erweiterbar

Die Tabelle zeigt, dass reines fetch mit useEffect in keiner Kategorie gegen eine dedizierte Bibliothek gewinnt, sondern lediglich in kleinen Prototypen ohne relevante Nebenläufigkeit vertretbar ist. Zwischen den drei Bibliotheken entscheidet vor allem der bestehende Stack: Wer bereits Redux im Projekt hat, profitiert von RTK Query, wer maximale Schlankheit will, greift zu SWR. Für React Native-Apps mit echtem Offline-Anspruch, Optimistic Updates und sauberer NetInfo-Integration bietet TanStack Query die vollständigste, offiziell dokumentierte Lösung ohne zusätzliche Wrapper-Bibliotheken.

10. Zusammenfassung

TanStack Query löst in React Native die drei zentralen Schwächen von plain fetch mit useEffect und useState: Race Conditions bei schneller Navigation, fehlendes Caching mit doppelten Requests und kein automatisches Neuladen beim Zurückkehren aus dem Hintergrund. Ein zentraler QueryClient mit mobil-tauglichen Defaults für staleTime und Retry-Verhalten bildet das Fundament, useQuery und useMutation ersetzen manuelles State-Management, und Query Keys mit Invalidation halten Listen und Detailansichten synchron.

Für die mobilspezifischen Anforderungen sorgt die Verdrahtung von onlineManager mit NetInfo für zuverlässiges Refetch-on-Reconnect, während focusManager über AppState Background Refetching beim App-Resume auslöst. Ein AsyncStorage-Persister über persistQueryClient sorgt dafür, dass Nutzer direkt nach dem Kaltstart bereits Daten sehen, statt auf einen leeren Cache zu starren, und useInfiniteQuery macht paginierte Listen ohne manuelles Offset-Tracking möglich.

TanStack Query in React Native, das Wichtigste auf einen Blick

QueryClient Setup

Ein zentraler QueryClient mit angepasstem staleTime, gcTime und Retry-Backoff, bereitgestellt über QueryClientProvider an der App-Wurzel.

useQuery & useMutation

Lesen über useQuery mit automatischer Deduplizierung, Schreiben über useMutation mit Query-Key-Invalidation und Optimistic Updates.

NetInfo & Persistenz

onlineManager mit NetInfo für Reconnect-Handling, AsyncStorage-Persister für Offline-Cache über App-Neustarts hinweg.

Infinite Queries

useInfiniteQuery mit getNextPageParam für paginierte FlatLists, ohne manuelles Offset- oder Seiten-Tracking im lokalen State.

11. FAQ: TanStack Query in React Native

1Was ist TanStack Query und wofür wird es genutzt?
Eine Server-State-Bibliothek, die Caching, Deduplizierung, Refetching und Fehlerbehandlung für REST-API-Aufrufe in React Native übernimmt.
2Unterschied zu fetch mit useEffect und useState?
Caching, Deduplizierung, automatische Retries und Refetching bei App-Resume oder Reconnect, alles ohne manuelle Zusatzlogik.
3Warum ist staleTime auf Mobilgeräten wichtig?
Verhindert unnötige Requests bei jeder Screen-Rückkehr und spart dadurch Datenvolumen und Akku auf mobilen Netzen.
4Wie sollten Query Keys strukturiert werden?
Als Array von generisch zu spezifisch, damit Invalidation präzise nur die betroffenen Query-Varianten erfasst.
5Was macht invalidateQueries genau?
Markiert passende Queries als veraltet und löst bei aktiven Komponenten automatisch einen Refetch aus.
6Wie funktioniert Rollback bei Optimistic Updates?
onMutate snapshotet den alten Stand, onError stellt ihn bei Fehlschlag wieder her, onSettled invalidiert abschließend.
7Warum reicht der Standard-onlineManager nicht?
Er basiert auf Browser-APIs, die in React Native fehlen. NetInfo muss manuell per setEventListener angebunden werden.
8Wann lohnt sich persistQueryClient?
Wenn Nutzer nach Kaltstart sofort sinnvolle Daten sehen sollen, statt auf einen leeren Cache zu warten.
9Wie liest getNextPageParam die nächste Seite?
Es erhält die letzte Seite als Argument und liefert den nächsten pageParam, etwa einen Cursor aus der API-Antwort.
10Wie sollte Retry-Verhalten mobil konfiguriert werden?
Zwei bis drei Versuche mit exponentiellem Backoff bis zu einer Obergrenze fangen kurze Aussetzer ab, ohne den Akku zu belasten.