Reputation: 537
I tried to use react-infinite-scroll-component
to get an infinite scrolling effect.
However, the arr
is updating but updating as full length array at the end.
And, I want it to update as slicing by 10 (like first 10, then 10, ...) till length of array using that package. So, array should be updated by length 10 only every 5 secs.
Note: I found below two stackoverflow links which was so messing me a lot!!
And, I couldn't understand anything (and they also use class component well I know how to implement it into functional but I believe something is wrong while mutating array!)
Here is the live demo: codesandbox link
Any suggestions, what is the problem?
Upvotes: 1
Views: 211
Reputation: 48733
Try this:
DataScroller
component that takes the data and a size i.e. 15arr
variabel in utils
to dynamically generate 120 recordsfetchMoreData
is now a callbackhasMore
upon data changesNote: 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.
import DataScroller from "./DataScroller";
import { arr } from "./utils";
export default function App() {
return (
<>
<div className="mt-24"></div>
<DataScroller data={arr} size={15} />
</>
);
}
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>
);
}
export const arr = Array.from({ length: 120 }, (_, i) => ({
id: i + 1,
name: "div"
}));
Upvotes: 0
Reputation: 1
I guess the issue is that the first10
state variable is not being updated correctly inside the setTimeout
callback function. I changed a few things in your code. Check if the following works for you as intended:
import { arr } from "./utils";
import InfiniteScroll from "react-infinite-scroll-component";
import { useState, useEffect } from "react";
export default function App() {
const [isLoading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const [first10, setFirst10] = useState(arr.slice(0, 10));
const fetchMoreData = () => {
if (arr.length >= 30) {
setHasMore(false);
return;
}
};
useEffect(() => {
fetchMoreData();
let insertAt = 10;
const interval = setInterval(() => {
if (insertAt >= arr.length) {
clearInterval(interval);
setHasMore(false);
return;
}
setFirst10((prevFirst10) => {
const nextSlice = arr.slice(insertAt, insertAt + 10);
insertAt += 10;
return [...prevFirst10, ...nextSlice];
});
}, 5000);
return () => clearInterval(interval);
}, []);
return (
<>
<div className="mt-24"></div>
<InfiniteScroll
dataLength={first10.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>
}
>
{first10.map((t) => (
<li key={t.id} className="mx-4 mt-8">
{t.name.concat(` ${t.id}`)}
</li>
))}
</InfiniteScroll>
</>
);
}
Upvotes: 0