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.
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.