n my implementation of infinite scroll without any library, I encountered a problem within my useEffect. When I scroll to the bottom, it triggers a request for the next set of data, which works perfectly. Initially, if I’m on Page 1 and reach the scroll end, it fetches the response for Page 2 as expected. However, when I scroll to the bottom again to fetch for the next page (Page 3), I noticed that it makes requests for Page 2 and then Page 3. Similarly, on Page 3, it requests Page 2, Page 3, and then Page 4. This results in infinite data being fetched.
My backend API is functioning correctly, and it handles pagination properly. The response from the backend API includes an error flag along with the error message if any, an array of chapters, the current page number, page size, total pages, and total number of chapters.
const [chaptersPayload, setChaptersPayload] = useState<ChapterPayload>({
chapters: [],
infiniteScrollChapters: [],
pageNumber: 1,
pageSize: 18,
totalPages: 1,
totalChapters: 0,
}); // Initially i have 18 items ie page 1
useEffect(() => {
const getChapters = async () => {
try {
const chaptersResponse = await fetch("/api/chapters");
const chaptersData = await chaptersResponse.json();
const { error, chapters, ...chaptersPayload } = chaptersData;
setChaptersPayload((prev) => ({
...prev,
chapters,
infiniteScrollChapters: chapters.slice(0, 18),
...chaptersPayload,
}));
} catch (error: any) {}
};
getChapters();
}, []);
useEffect(() => {
document.body.style.overflow = seeAll ? "hidden" : "auto";
const loadMore = async () => {
try {
setInfiniteScrollLoading(true);
const chaptersResponse = await fetch(
`/api/chapters?pagination=true&pageNumber=${chaptersPayload.pageNumber + 1}`,
);
const chaptersData = await chaptersResponse.json();
console.log(chaptersData);
const { error, chapters, ...restOfChaptersPayload } = chaptersData;
setChaptersPayload((prev) => ({
...prev,
infiniteScrollChapters: [...prev.infiniteScrollChapters, ...chapters],
...restOfChaptersPayload,
}));
} catch (error: any) {
} finally {
setInfiniteScrollLoading(false);
}
};
const handleScroll = () => {
const container = containerRef.current;
if (container) {
const bottomOffset = container.scrollHeight - container.clientHeight;
const scrolledToBottom = container.scrollTop >= bottomOffset * 0.96;
if (
scrolledToBottom &&
!infiniteScrollLoading &&
chaptersPayload.pageNumber !== chaptersPayload.totalPages
) {
loadMore();
}
}
};
if (seeAll) {
containerRef.current?.addEventListener("scroll", handleScroll);
} else {
containerRef.current?.removeEventListener("scroll", handleScroll);
}
}, [seeAll, infiniteScrollLoading, chaptersPayload])
<div
ref={containerRef}
className="fixed bottom-0 left-0 z-[60] h-[90vh] w-full overflow-auto rounded-t-[16px] bg-white"
>
{List Render}
</div>
return NextResponse.json(
{
error: true,
message: error.message,
chapters: [],
pageNumber: pageNumber,
pageSize: pageSize,
totalPages: Math.ceil(chapters.length / pageSize),
totalChapters: chapters.length,
},
{
status: 500,
},
)