Infinite Scroll in React - Without External Libraries
Add infinite scrolling to your react app without any dependencies
Infinite Scroll is an effect we put on websites to create a seamless user experience. This effect is no magic, it is just some clever use of JavaScript to give the website a better overall experience.
This technique is used on many websites, especially those with a feed, e.g. YouTube.
So how does this thing works?
Let's discuss the basic idea of Infinite Scrolling.
In an Infinite Scroll, the user is shown a single page with limited results. When the user reaches the end of those results, more content is loaded, and this goes on.
So what actually happens here?
For an Infinite Scroll, we prefer an API that has pagination enabled. So first, we simply request the first page from the API. Now when the user reaches the end of the page, a new API call is made with the next page number.
As you might have noticed from the above paragraph, we make the API call when we reach the end of the page. There are two ways to detect the end of the page. Either the page is fully scrolled, or the last element is fully visible on the screen. In this article, we are going to learn how to exactly do this.
We will discuss two methods of implementing Infinite Scroll
Prerequisites
Knowledge of React Hook: useState, useRef, useEffect
A basic react application setup
Implementation - #1
In this method, we will use the different values of windows that are provided by the browser.
We need to attach a scroll event listener to the window. This will be done inside useEffect
because the listener needs to be attached as soon as the component is mounted.
useEffect(() => {
window.addEventListener("scroll",handleInfiniteScroll);
return () => window.removeEventListener("scroll", handleInfiniteScroll);
},[])
When the component is loaded, we have attached a Scroll Event listener to the page which will run handleInfiniteScroll
the method. Then we remove that event listener in the cleanup method of useEffect
.
Try to remove the cleanup method (return) in the
useEffect
and run the code. Observer carefully how the requests are being made then.
Let's define handleInfiniteScroll
method
//states
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(true);
//method
const handleInfiniteScroll = async () => {
try {
if (
window.innerHeight + window.document.documentElement.scrollTop + 1 >=
window.document.documentElement.scrollHeight
) {
setLoading(true);
setPage((prev) => prev + 1);
}
} catch (error) {
console.error(error);
}
};
We have declared two states here, page
keeps track of the page number because our API supports pagination so we need to pass a page number to it.
In the handleInfiniteScroll
method, we are checking for the condition that, the sum of window.innerHeight
and window.document.documentElement.scrollTop
+ an additional number of pixels is greater than equal to window.document.scrollHeight.
window.innerHeight
: Returns the interior height of the window in pixelswindow.document.documentElement.scrollTop
: Returns the number of pixels that are scrolled verticallywindow.document.documentElement.scrollHeight
: Returns the total height of content (which is yet not visible on the screen)
So when innerHeight
and scrollTop
are added together they will always result in scrollHeight
. You can verify this by doing a console log of these values and checking them manually.
This method will make changes to the state page. So we will add an useEffect
which will call our API.
//state
const [card, setCard] = useState([])
//method
const getCardData = async () => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=9&_page=${page}`
);
const data = await res.json();
//solved: the first page is repeated twice
if (page !== 1) {
setCard((prev) => [...prev, ...data]);
} else {
setCard([...data]);
}
setLoading(false);
};
//useEffect
useEffect(() => {
getCardData();
}, [page]);
This piece of code is really simple. All we have done here is called the API and stored the data in setCard()
(probably not a good name ๐
)
Now that we have all the main code setup we can simply pass our data which is in card
to a component that will render the items.
And THAT'S IT!!
You get an infinite scroll there.
Here is a live demo of the app that I created: https://effortless-granita-f1a33d.netlify.app/
And you can get the code here: https://github.com/theshubhagrwl/infinite-scroll-react-window
Implementation - #2
In this... well let's continue this is next article.
To give you a hint, in the second approach we will use the IntersectionObserver
API
Good Day!