
Creating Infinite Scroll in React/Next.js using Intersection Observer API
Introduction
Have you ever wondered how infinite scroll works on websites like Facebook, Twitter, or Instagram work? In this tutorial, we will learn how to implement infinite scroll in a React or Next.js application using the Intersection Observer API.
Intersection Observer API
The Intersection Observer API is a modern web API that allows us to observe changes in the intersection of a target element with an ancestor element or the viewport. This API is commonly used to implement features like lazy loading of images, infinite scroll, and more. Earlier infinite scroll was usually implemented using scroll event listeners, but the Intersection Observer API provides a more efficient way now to detect when an element comes into view.
Now let's see how we can use this API to implement infinite scroll in a React component.
Posts Component
Say we have a Posts
component that fetches a list of posts from an API and renders them as a list of cards. We will implement infinite scroll to load more posts as the user scrolls down the page.
Initially we will start without infinite scroll, we are just displaying a list of posts from a single call to the API.
import React, { useEffect, useState } from "react"; import { getPosts } from "./actions"; import Post from "./post"; export default function Posts() { const [posts, setPosts] = useState<Post[]>([]); useEffect(() => { const fetchPosts = async () => { try { const response = await getPosts(0); // getPosts calls the API to fetch posts passing page number. We are passing 0 to get the first page data. setPosts(response.data); } catch (error) { console.error("Error fetching posts:", error); } }; fetchPosts(); }, []); return ( <div> {posts.map((post) => ( <Post key={post.id} post={post} /> // Post displays post data in card format ))} </div> ); }
Implementing Infinite Scroll
To implement infinite scroll, we need to do the following:
Add State for Pagination details and Loading status
const [page, setPage] = useState<number>(0); const [hasMore, setHasMore] = useState<boolean>(true); const [isLoading, setIsLoading] = useState(false);
Use Intersection Observer to Detect Scroll
If we directly use the Intersection Observer API, we need to handle the observer setup and teardown, which can be complex. Instead, we can use the react-intersection-observer
library, which provides a React hook to easily observe elements in the viewport.
We will use the useInView
hook from the react-intersection-observer
library to detect when the user has scrolled to the bottom of the list. When the last post is in view, we will load more posts by calling the fetchPosts
function with the next page number.
Here is the final implementation of the Posts
component with infinite scroll:
import React, { useEffect, useState } from "react"; import { getPosts } from "./actions"; import Post from "./post"; import { useInView } from "react-intersection-observer"; export default function Posts() { const [posts, setPosts] = useState<Post[]>([]); const [page, setPage] = useState<number>(0); const [hasMore, setHasMore] = useState<boolean>(true); const [isLoading, setIsLoading] = useState(false); const [scrollTrigger, isInView] = useInView(); const fetchPosts = async (page: number) => { setIsLoading(true); try { const response = await getPosts(page); setPosts((prevPosts) => [...prevPosts, ...response.data]); setHasMore(response.data.length > 0); } catch (error) { console.error("Error fetching posts:", error); } finally { setIsLoading(false); } }; useEffect(() => { fetchPosts(page); }, [page]); useEffect(() => { if (isInView && hasMore && !isLoading) { setPage((prevPage) => prevPage + 1); } }, [isInView, hasMore, isLoading]); return ( <div> {posts.map((post) => ( <Post key={post.id} post={post} /> // Displays post data in card format ))} {(hasMore && <div ref={scrollTrigger}>Loading...</div> ) || ( <p className="...">No more posts to load</p> )} ); }
useInView
hook returns 2 values, scrollTrigger
and isInView
. scrollTrigger
is a ref that you need to attach to the element you want to observe. In this case, we attach it to a div
element at the end of the list of posts. isInView
is a boolean value that indicates whether the element with the scrollTrigger
ref is in view or not.
When the scrollTrigger
element comes into view, we increment the page
state to load more posts. The fetchPosts
function is called whenever the page
state changes, which fetches the posts for the given page number and appends them to the existing list of posts.
You can find the complete source code here
Conclusion
In this tutorial, we learned how to implement infinite scroll in a React or Next.js application using the Intersection Observer API. By using the react-intersection-observer
library, we were able to detect when the user has scrolled to the bottom of the list and load more posts dynamically. This technique can be applied to various scenarios where you need to load content as the user scrolls down the page.
To stay updated with the latest web development tutorials, follow us on youtube, linked in and medium.
Video Version
In the below video, you can find more detailed explanation of the above implementation.
Related Posts
Evolution of HTTP: Comparing HTTP/0.9, HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3
Explore the evolution of the HTTP protocol, comparing HTTP/0.9, HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3. Understand their improvements, drawbacks, and use cases.
Docker Basics for Developers
Learn the basics of Docker, a powerful tool for developing, shipping, and running applications. This guide covers setting up Docker, creating and managing containers, and best practices for developers.