useEffect is getting called multiple times (ReactJs)

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;

The useEffect is effectively called two times do to strict mode.
For what I see I think the problem could be in the getPosts method.
If it returns every post till pageNum * limit, than you should change the setData call, because right now you are adding every post for every call of setData.

first call: 0 + 10 posts
second call: 10 + 10 posts

if you call it for the second page it will add 20 posts to the 20 posts you already have.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.