Infinite scroll with Intersection Observer

Maya Patel Jan 2026
2 tabs
import { useInfiniteQuery } from '@tanstack/react-query'
import api from '@/services/api'
import { Post, PaginatedResponse } from '@/types'

export function useInfinitePosts() {
  return useInfiniteQuery({
    queryKey: ['posts', 'infinite'],
    queryFn: async ({ pageParam = 1 }) => {
      const { data } = await api.get<PaginatedResponse<Post>>('/posts', {
        params: { page: pageParam },
      })
      return data
    },
    getNextPageParam: (lastPage) => {
      const { current_page, total_pages } = lastPage.meta
      return current_page < total_pages ? current_page + 1 : undefined
    },
    initialPageParam: 1,
  })
}
2 files · typescript Explain with highlit

Infinite scroll loads more content as users reach the bottom of a list, improving perceived performance over pagination. I use the Intersection Observer API to detect when a sentinel element becomes visible, then trigger the next page fetch. React Query's useInfiniteQuery manages pagination state and combines pages into a flattened list. The getNextPageParam function extracts pagination metadata from the API response to determine if more pages exist. Each new page appends to the existing data array. I also provide a 'Load More' button as a fallback for users who prefer manual control or when JavaScript fails. This pattern works great for feeds, search results, or any long lists.