~/swaraj.dev
Back to all posts
January 25, 20262 min read

Integrating REST APIs in React Native with React Query

Fetch, cache, and sync server data in React Native the right way � using React Query for loading states, error handling, and cache invalidation.

react-nativejavascriptapireact-query

The Problem with useEffect + fetch

Manually managing loading, error, and data state for every API call is tedious and error-prone. You end up with the same three useState calls on every screen component.

React Query to the Rescue

npx expo install @tanstack/react-query

Setup

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

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

Fetching Data

function PostsScreen() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['posts'],
    queryFn: () => fetch('/api/posts').then(r => r.json()),
  });

  if (isLoading) return <ActivityIndicator />;
  if (error) return <ErrorView />;

  return <FlatList data={data} renderItem={renderPost} />;
}

Mutations and Cache Invalidation

const mutation = useMutation({
  mutationFn: (newPost) => api.post('/posts', newPost),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['posts'] });
  },
});

Key Features

  • Automatic background refetching when the app returns to foreground
  • Stale-while-revalidate caching
  • Retry on failure with configurable backoff
  • Parallel queries with useQueries
  • Infinite scroll with useInfiniteQuery

Conclusion

React Query eliminates 80% of data-fetching boilerplate and handles edge cases (refetch on focus, network reconnect, request deduplication) that manual fetch code misses entirely.