How would you implement infinite scrolling in React?

Design and implement a production-ready infinite scroll in React β€” covers IntersectionObserver, performance, virtualization, and UX tradeoffs.

advancedUi patternsreactinfinite scrollintersectionobservervirtualization
Published: 11/18/2025
Updated: 11/18/2025

Advertisement

How would you implement infinite scrolling in React?

🧩 Scenario

You need to build an infinite-scrolling list component used across the app (feeds, search results).

Requirements:

  • Load next page when the user scrolls near the bottom
  • Show loading state and error handling
  • Avoid duplicate requests and race conditions
  • Support refreshing and manual "Load more"
  • Be performant for long lists (optionally support virtualization)

Implement a production-ready example and explain tradeoffs.


🧠 Answer (Design + Rationale)

Key decisions:

  1. Use IntersectionObserver on a sentinel element rather than scroll events β€” it's more efficient and works with container-based scrolling.
  2. Keep pagination and loading state in a hook (useInfiniteScroll) so it’s reusable.
  3. Deduplicate requests by tracking isLoading and hasMore.
  4. Provide manual fallback ("Load more" button) for browsers where IntersectionObserver might be blocked.
  5. For very long lists, combine with virtualization (e.g., react-window or react-virtual) β€” we show a simple optional hook comment for that.
  6. Handle aborting/stale responses using AbortController or request tokens.

Tradeoffs:

  • IntersectionObserver avoids expensive scroll handlers but requires a DOM sentinel and is not supported in very old browsers (polyfills exist).
  • Virtualization reduces DOM nodes at the cost of more complex layout (sticky headers, varying item heights).
  • Server-driven cursors (cursor-based pagination) are preferred over page-numbering for real-time feeds.

🎯 Live Demo


πŸ” Real-World Example & Tips

  • Use cursor-based pagination (cursor/token) when items are real-time or frequently changing.
  • Debounce rapid scroll events when using scroll listeners β€” IntersectionObserver avoids this overhead.
  • For varying item heights, virtualization libraries that support dynamic heights (e.g., react-virtual) are preferable.
  • Always show a manual fallback action β€” "Load more" β€” to improve accessibility and resilience.
  • Remember to cancel in-flight requests when component unmounts to avoid state updates on unmounted components.

🧭 Diagram (Flow)

sequenceDiagram participant UI participant Hook participant API UI->>Hook: component mount -> initial load Hook->>API: fetch page 0 API-->>Hook: return items Hook-->>UI: set items UI->>UI: user scrolls -> sentinel intersects UI->>Hook: loadNext() Hook->>API: fetch page N API-->>Hook: return items Hook-->>UI: append items

βœ… Quick Practice

  1. Replace fakeFetch with a real API. Use AbortController to cancel stale requests.
  2. Integrate react-window for virtualization and measure performance.
  3. Change rootMargin to experiment how early fetching happens.

Summary

  • Use IntersectionObserver for efficient infinite scroll.
  • Keep load logic in a reusable hook and guard against duplicate requests.
  • Combine with virtualization for large lists and provide manual fallback UX.
Frequently Asked Questions

Should I use window scroll or a container scroll?

Prefer container scroll or IntersectionObserver on a sentinel. Window scrolling works but is harder to isolate for components and tests.

When to use virtualization with infinite scroll?

When the list could grow large (thousands of items) or each item is heavy. Virtualization prevents DOM bloat.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement