Capítulo 22 de 80
Naively keying a query by page number treats each page as a brand-new query, so the UI flashes between success and pending on every page change — placeholderData: keepPreviousData keeps the previous page's data on screen while the next page loads instead.
useQuery({ queryKey: ['projects', page], queryFn: () => fetchProjects(page) }) "works," but each page value is a distinct cache entry, so switching pages destroys/creates queries and the UI drops to a loading state every time.keepPreviousData: passed as placeholderData, it keeps the last successful page's data visible while the new page's key is fetching, then swaps seamlessly once the new data arrives — no hard loading flash.isPlaceholderData: exposed on the result to distinguish "this is stale data from the previous page, still fetching the real one" from genuinely fresh data — use it to disable a "Next" button until you know a next page actually exists, since the currently-shown data might be the previous page's.placeholderData (with keepPreviousData) applies equally to useInfiniteQuery, letting cached pages stay visible while the infinite query's key changes.import { keepPreviousData, useQuery } from '@tanstack/react-query'
const { data, isFetching, isPlaceholderData } = useQuery({
queryKey: ['projects', page],
queryFn: () => fetchProjects(page),
placeholderData: keepPreviousData,
})
// disabled until we know the *current* (non-placeholder) data confirms a next page
<button disabled={isPlaceholderData || !data?.hasMore} onClick={() => setPage((p) => p + 1)}>
Next Page
</button>
keepPreviousData eliminating the flash between pages, and isPlaceholderData gating a "Next" action on genuinely-fresh data.placeholderData: keepPreviousData — it's the general fix, not something specific to numeric pages.!isPlaceholderData, since the visible data might still be the previous key's result.placeholderData applies there too.