Infinite Scroll in JS & React

In JS:
Infinite scroll is a technique used in web development to load content dynamically as the user scrolls down a webpage, creating an endless scrolling effect without requiring the user to navigate to a new page. Below is a basic example of how to implement infinite scroll using JavaScript:

HTML Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinite Scroll Example</title>
    <style>
        /* Basic styling */
        body {
            font-family: Arial, sans-serif;
        }
        #content {
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
        }
        .post {
            margin: 20px 0;
            padding: 15px;
            border: 1px solid #ddd;
            background-color: #f9f9f9;
        }
    </style>
</head>
<body>
    <div id="content">
        <!-- Posts will be added here dynamically -->
    </div>

    <script src="infinite-scroll.js"></script>
</body>
</html>

JavaScript Implementation

// infinite-scroll.js
document.addEventListener("DOMContentLoaded", function() {
    const content = document.getElementById('content');
    let page = 1;

    function loadPosts(page) {
        // Simulate fetching data from an API
        return new Promise((resolve) => {
            setTimeout(() => {
                let posts = '';
                for (let i = 1; i <= 10; i++) {
                    posts += `<div class="post">Post ${((page - 1) * 10) + i}</div>`;
                }
                resolve(posts);
            }, 1000);
        });
    }

    async function addPosts() {
        const posts = await loadPosts(page);
        content.innerHTML += posts;
        page++;
    }

    function handleScroll() {
        if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) {
            addPosts();
        }
    }

    // Initial load
    addPosts();

    // Attach the scroll event listener
    window.addEventListener('scroll', handleScroll);
});

How It Works:

  1. HTML Structure: The #content div is where posts are dynamically added.

  2. JavaScript Logic:

    • loadPosts(): Simulates an API call by returning a promise that resolves after a short delay with 10 new posts.

    • addPosts(): Calls loadPosts() to get new posts and appends them to the #content div.

    • handleScroll(): Checks if the user has scrolled near the bottom of the page. If so, it loads more posts.

    • Event Listener: The scroll event listener triggers the handleScroll() function to load new content when necessary.

This basic example simulates an API call with a delay. In a real-world scenario, you would replace loadPosts() with an actual API call to fetch new content.

\============================================

In React:
To implement infinite scroll in React, you can follow these steps:

1. Set Up State and Effect

Start by setting up state to track the items to be displayed and an effect to handle the scroll event.

import React, { useState, useEffect } from 'react';

const InfiniteScroll = () => {
  const [items, setItems] = useState(Array.from({ length: 20 }));
  const [hasMore, setHasMore] = useState(true);

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const handleScroll = () => {
    if (
      window.innerHeight + document.documentElement.scrollTop >=
      document.documentElement.offsetHeight - 100
    )
      return;
    loadMoreItems();
  };

  const loadMoreItems = () => {
    if (!hasMore) return;

    setTimeout(() => {
      setItems((prevItems) => [
        ...prevItems,
        ...Array.from({ length: 20 }),
      ]);
    }, 1500);
  };

  return (
    <div>
      {items.map((_, index) => (
        <div key={index} style={{ height: 50, border: '1px solid black', margin: '10px 0' }}>
          Item {index + 1}
        </div>
      ))}
      {hasMore && <p>Loading more items...</p>}
    </div>
  );
};

export default InfiniteScroll;

2. Key Components:

  • State (items): Holds the list of items to display. Initially, it starts with a set number of items (20 in this case).

  • State (hasMore): Tracks whether more items can be loaded.

  • Effect (useEffect): Sets up an event listener for the scroll event when the component mounts and cleans it up when the component unmounts.

  • Scroll Handler (handleScroll): Checks if the user has scrolled to the bottom of the page and triggers loading more items if true.

  • Loading More Items (loadMoreItems): Simulates an API call by adding more items to the list with a delay.

3. Behavior:

  • Condition Check:

    • The if condition checks if the user has scrolled near the bottom of the page. Specifically, it checks if the sum of the viewport height (window.innerHeight) and the vertical scroll position (document.documentElement.scrollTop) is greater than or equal to the total height of the document minus 100 pixels (document.documentElement.offsetHeight - 100).
  • Early Return:

    • No Loading: If the condition is met, meaning the user is within 100 pixels of the bottom of the page, the function immediately returns and does not call loadMoreItems().

    • Loading More: If the condition is not met, the function proceeds to call loadMoreItems(), which would load additional items.

4. Rendering the Component:

You can render this component in your app by importing and using it in your main component:

import React from 'react';
import ReactDOM from 'react-dom';
import InfiniteScroll from './InfiniteScroll';

ReactDOM.render(<InfiniteScroll />, document.getElementById('root'));

This basic implementation can be expanded with real API calls, loading indicators, and more sophisticated logic for stopping the scroll when no more items are available.

Did you find this article valuable?

Support Tushar Khanna's Blog by becoming a sponsor. Any amount is appreciated!