# Fetching Data — React Native

Source: https://www.skillbyai.com/en/react-native/d-fetch

> fetch plus a server-state library.

## fetch and TanStack Query

React Native provides the standard `fetch` API, so any HTTP client works. Doing it by hand in `useEffect` means writing loading, error, retry, caching and refetch logic yourself. **TanStack Query** (React Query) manages **server state**: `useQuery` caches results by a query key, deduplicates requests, retries failures and refetches stale data; `useMutation` handles writes and lets you invalidate related queries. On mobile, wire its `focusManager` to `AppState` so data refreshes when the app returns to the foreground, and its `onlineManager` to a network-status library so it pauses while offline. Remember that phones lose connectivity often, so design loading, error and empty states for every screen.

## Remote data, local data, app state

Server data needs caching and retries, local data needs the right storage, and app state needs a simple home.

![Three ideas: fetching with TanStack Query, storage options, state management choices.](assets/figures/react-native/section-5-map.svg) — Figure 5.1 — Server state, device storage and client state.

## Loading products with useQuery

TanStack Query v5-style API; check the docs for your version.

```tsx
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
import { ActivityIndicator, FlatList, Text } from "react-native";

const queryClient = new QueryClient();

type Product = { id: string; name: string };

async function fetchProducts(): Promise<Product[]> {
  const res = await fetch("https://api.example.com/products");
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

function Products() {
  const { data, isPending, isError, refetch, isRefetching } = useQuery({
    queryKey: ["products"],
    queryFn: fetchProducts,
  });
  if (isPending) return <ActivityIndicator />;
  if (isError) return <Text onPress={() => refetch()}>Could not load. Tap to retry.</Text>;
  return (
    <FlatList
      data={data}
      keyExtractor={(p) => p.id}
      renderItem={({ item }) => <Text>{item.name}</Text>}
      refreshing={isRefetching}
      onRefresh={refetch}
    />
  );
}

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

## localhost is not your computer

On a physical device, localhost means the phone itself. Use your machine's LAN address or a tunnel, and remember that release builds generally require HTTPS (iOS App Transport Security, Android cleartext rules).

**Quiz:** What does TanStack Query mainly manage for you?

- [ ] Native view layout
- [x] Server state: caching, deduplication, retries and refetching of remote data
- [ ] App signing keys
- [ ] Push notification tokens on the server

*Answer:* Server state: caching, deduplication, retries and refetching of remote data. It treats remote data as a cache.
