Try this:
- I created a DataScrollercomponent that takes the data and a size i.e. 15
- I modified the arrvariabel inutilsto dynamically generate 120 records
- fetchMoreDatais now a callback
- There is an effect to set hasMoreupon data changes
Note: I updated react-infinite-scroll-component to 6.1.0 (latest version available as of this post). I was getting a lot of Warning with the version you were using.
App.js
import DataScroller from "./DataScroller";
import { arr } from "./utils";
export default function App() {
  return (
    <>
      <div className="mt-24"></div>
      <DataScroller data={arr} size={15} />
    </>
  );
}
DataScroller.js
import { useCallback, useEffect, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
export default function DataScroller({ data, size }) {
  const [hasMore, setHasMore] = useState(data.length > size);
  const [visibleData, setVisible] = useState(data.slice(0, size));
  const fetchMoreData = useCallback(() => {
    setTimeout(() => {
      setVisible((currentData) => {
        const startIndex = currentData.length;
        const endIndex = Math.min(startIndex + size, data.length);
        return structuredClone(currentData).concat(
          data.slice(startIndex, endIndex)
        );
      });
    }, 1000);
  }, [data, size]);
  useEffect(() => {
    setHasMore(visibleData.length < data.length);
  }, [data, visibleData]);
  return (
    <InfiniteScroll
      dataLength={visibleData.length}
      next={fetchMoreData}
      hasMore={hasMore}
      loader={<h3 className="font-bold text-2xl">Loading...</h3>}
      endMessage={
        <p className="text-base my-4 font-medium text-center">
          <b>Yay! You have seen it all</b>
        </p>
      }
    >
      {visibleData.map((t) => (
        <li key={t.id} className="mx-4 mt-8">
          {" "}
          {t.name.concat(` ${t.id}`)}
        </li>
      ))}
    </InfiniteScroll>
  );
}
utils.js
export const arr = Array.from({ length: 120 }, (_, i) => ({
  id: i + 1,
  name: "div"
}));