I’m facing some issues while building an Infinite scroll using ReactJs and Intersection observer API.
On Loading the application for the first time, the API is being called twice instead of once. I think this is happening because of strict mode but not 100% sure. And when I make some changes within the InfiniteScroll
component (such as changing the text from “Loading” to “Loading…”), the useEffect hook of the usePosts
hook is triggered again. As a result, the API is called once more with page=1
, causing the setData((prevData) => [...prevData, ...posts]);
setter function to add duplicate data to the data array. Ideally, the hook should only execute when the component is initially mounted and when there are changes to the pageNum
dependency of the useEffect.
Anyone please help me to fix this issue.
Codesandbox Link: optimistic-satoshi-rnrhsr - CodeSandbox
InfiniteScroll:
import { useRef, useState } from "react";
import usePosts from "./usePosts";
const InfiniteScroll = () => {
const [page, setPage] = useState(1);
const lastPostRef = useRef();
const { data, loading, isLastPage } = usePosts(page); // Todo: add error
const content = data.map((post, i) => {
if (data.length === i + 1) {
return (
<p key={post.id} ref={lastPostRef}>
{post.title}
</p>
);
}
return <p key={post.id}>{post.title}</p>;
});
return (
<div>
{content}
{loading && <p className="center">Loading More Posts...</p>}
</div>
);
};
export default InfiniteScroll;
usePosts.js
import { useEffect, useState } from "react";
import { getPosts } from "./api";
const usePosts = (pageNum) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [isLastPage, setIsLastPage] = useState(false);
useEffect(() => {
const getData = async () => {
const { posts, total, skip, limit } = await getPosts(pageNum, 10);
setData((prevData) => [...prevData, ...posts]);
setLoading(false);
if (total === skip * limit) setIsLastPage(true);
};
getData();
}, [pageNum]);
return { data, loading, isLastPage };
};
export default usePosts;