Infinite Queries and Pagination Patterns
Learn how React Query coordinates pagination to ensure rendering remains stable, resumable, and predictable.
As applications evolve, lists stop behaving like simple data. Feeds grow longer, search results stretch across pages, and users expect to scroll continuously without losing context. What initially works as fetch page 1, then page 2 quickly becomes a source of architectural strain. Each page fetch is treated as a separate event, and the component becomes responsible for stitching results together, tracking pagination state, and preventing duplicate or out-of-order requests.
In many React applications, this logic lives directly in components. State tracks the current page. Effects trigger fetches when that page changes. Results are appended manually, often guarded by ad hoc flags like isLoadingMore or hasMore. As soon as users scroll faster than the network can keep up, race conditions occur. Loading indicators flash inconsistently. Navigating away and back resets the list, even though the data was already fetched moments ago. The UI becomes tightly coupled to the mechanics of pagination rather than the meaning of the data.
The core issue is that paginated data is still server state, but it is treated as ephemeral, component-owned state. There is no durable representation of “the list so far,” no shared cache that understands which pages exist, and no coordination between rendering and background loading. Each render rebuilds the list around the next fetch, making large collections feel fragile and unpredictable.
React Query’s infinite query model addresses this mismatch. Instead of asking components to orchestrate pagination, it elevates paginated data into a single, long-lived cache entry that grows over time. The cache, not the component, decides what pages exist, what page comes next, and how loading progresses. Rendering becomes a matter of reading the current snapshot, while the cache absorbs the complexity of pagination.
The above diagram shows two approaches. In the first, each scroll event triggers a new fetch that mutates local state, causing the list to rebuild and loading indicators to appear unpredictably. In the second, an infinite query cache holds an ordered stack of pages. The UI reads from the combined snapshot, while the cache fetches the next page independently and appends it internally.
Infinite queries: Calm rendering from a growing Cache
An infinite ...