ReviseAlgo Logo

Machine Coding

Infinite Scroll

Master building an Infinite Scroll component in React, covering Intersection Observer API, scroll-based data fetching, loading indicators, and scroll performance optimizations.

Last Updated: July 15, 2026 13 min read

1. Learning Objectives

In this challenge, you will build an Infinite Scroll component. By the end of this guide, you will be able to:

  • Use the IntersectionObserver API to detect when a sentinel element enters the viewport.
  • Fetch and append paginated data when the user scrolls to the bottom.
  • Manage loading states, error handling, and "no more data" indicators.
  • Clean up observers properly using useEffect return functions.
  • Prevent duplicate fetch requests using loading guards.

2. Overview

Infinite Scroll is a UI pattern that loads content continuously as the user scrolls, replacing traditional pagination buttons. It is commonly tested in machine coding interviews because it involves API integration, browser APIs, ref management, and performance considerations.

3. Why This Challenge Matters

Infinite scroll teaches critical patterns for production applications:

  • Browser API Integration: Using IntersectionObserver is more performant than scroll event listeners and teaches you how to integrate browser APIs with React's lifecycle.
  • Paginated Data Management: Appending new data to existing lists without replacing them is a pattern used in social feeds, search results, and product catalogs.

4. Real-World Analogy

Think of infinite scroll like reading a newspaper on a microfiche machine:

  • The Viewport: The machine's viewing window shows only a small portion of the film at a time — this is the visible part of your scrollable list.
  • The Sentinel: A small mark at the bottom of each frame tells the machine to advance to the next reel — this is the invisible sentinel element observed by IntersectionObserver.
  • Loading the Next Reel: When the mark enters the viewport, the machine loads the next reel (fetches the next page of data) and seamlessly continues.

5. Core Concepts

Below is a comparison of scroll event listeners versus Intersection Observer:

Property Scroll Event Listener Intersection Observer
Performance Fires on every pixel scrolled; requires throttling or debouncing. Fires only when an element enters or exits the viewport; inherently efficient.
Setup Manual addEventListener and manual calculation of scroll positions. Declarative: create an observer, point it at a DOM element, and define a callback.
Cleanup Must removeEventListener in useEffect cleanup. Call observer.disconnect() in useEffect cleanup.
Recommended Legacy approach Modern recommended approach

6. Syntax & API Reference

This example shows how to set up an Intersection Observer with a React ref:

7. Visual Diagram

This diagram shows the infinite scroll fetch cycle:

8. Live Example — Full Working Code

Below is a complete HTML page demonstrating infinite scroll with a mock API using setTimeout:

What just happened? A sentinel <div> sits at the bottom of the list. When it enters the viewport, the IntersectionObserver fires, triggering the next page fetch. New items are appended to the existing array, pushing the sentinel further down for the next trigger.

9. Interactive Playground

Try It Yourself Challenges:

  1. Add error handling: simulate a network failure on page 3 and display a "Retry" button.
  2. Add a "scroll to top" floating button that appears when the user has scrolled past 20 items.

10. Common Mistakes

Mistake Why it happens Wrong Correct
Duplicate fetch requests The observer callback fires multiple times while data is still loading, triggering concurrent fetches for the same page. if (entries[0].isIntersecting)
fetchData();
if (entries[0].isIntersecting
&& !loading && hasMore)
fetchData();
Replacing items instead of appending Using setItems(data) replaces the entire list with just the new page data, losing all previously loaded items. setItems(newData); setItems(prev =>
[...prev, ...newData]);

11. Best Practices

  • Use IntersectionObserver over scroll events: It is more performant and doesn't require manual throttling or debouncing.
  • Guard against duplicate fetches: Always check that loading is false and hasMore is true before initiating a fetch.
  • Disconnect observers on cleanup: Always disconnect or unobserve in the useEffect cleanup function to prevent memory leaks.
  • Show end-of-list indicators: Let users know when there is no more content to load, instead of showing an infinite loading spinner.

12. Browser Compatibility/Requirements

The IntersectionObserver API is supported in all modern browsers (Chrome 58+, Firefox 55+, Safari 12.1+, Edge 16+). For older browsers, you can use the intersection-observer polyfill.

13. Interview Questions

Q1: Why is IntersectionObserver preferred over scroll event listeners for infinite scroll?

Answer: Scroll event listeners fire on every pixel scrolled, which is very frequent and can cause performance issues (layout thrashing). IntersectionObserver only fires when the observed element enters or exits the viewport, making it inherently more efficient without needing manual throttling.

Q2: How do you prevent duplicate API calls in infinite scroll?

Answer: Maintain a loading boolean state variable. Set it to true before the fetch starts and false after it completes. In the observer callback, check that loading is false before triggering a new fetch. Also check a hasMore flag to stop fetching when all data has been loaded.

14. Debugging Exercise

Identify why the infinite scroll fetches the same page repeatedly without advancing:

View Solution

Diagnosis: The page state variable is never incremented after a successful fetch. Every call fetches page 1. Additionally, setItems([...items, ...data]) uses the stale items closure value instead of the functional updater.

Fix: Increment the page and use the functional updater for items:

15. Practice Exercises

Exercise 1: Bidirectional infinite scroll

Implement a chat-style infinite scroll that loads older messages when the user scrolls to the top and newer messages when they scroll to the bottom. Use two sentinel elements (one at the top, one at the bottom) with separate observers.

16. Scenario-Based Challenge

The virtualized infinite scroll challenge:

Your infinite scroll feed has grown to 10,000+ items. The page becomes sluggish because all 10,000 DOM elements exist simultaneously. Describe how you would combine infinite scroll with list virtualization (rendering only visible items) to maintain performance while still supporting unlimited scrolling.

17. Quick Quiz

Q1: What does the threshold option in IntersectionObserver control?

A) The distance from the viewport edge at which the callback fires

B) The percentage of the target element that must be visible before the callback fires

C) The maximum number of times the callback can fire

Answer: B — A threshold of 0.5 means the callback fires when 50% of the element is visible. A threshold of 1.0 means the entire element must be visible.

18. Summary & Key Takeaways

  • Use IntersectionObserver to detect when a sentinel element enters the viewport.
  • Append new data to existing items using the functional state updater: setItems(prev => [...prev, ...newData]).
  • Guard against duplicate fetches with loading and hasMore flags.
  • Always disconnect observers in useEffect cleanup functions.

19. Cheat Sheet

Operation Syntax Pattern
Create observer new IntersectionObserver(callback, { threshold: 1.0 })
Observe element observer.observe(sentinelRef.current)
Cleanup return () => observer.disconnect()
Append data setItems(prev => [...prev, ...newData])
---