constMAX_PAGES=5;constApp=()=>{const[items,setItems]=React.useState([]);const[isLoading,setIsLoading]=React.useState(false);const[hasMore,setHasMore]=React.useState(true);const[pages,setPages]=React.useState(0);constobserver=React.useRef();React.useEffect(()=>{// generating the 1st page on Component MountingupdateItems();setPages((pages)=>pages+1);},[]);constlastItemRef=React.useCallback((node)=>{// ensuring redundant calls are not made once the data is already BEING updatedif (isLoading)return;if (observer.current)observer.current.disconnect();observer.current=newIntersectionObserver((entries)=>{if (entries[0].isIntersecting&&hasMore){if (pages<MAX_PAGES){// adding more data only if:// 1. MORE data exists ("hasMore" - simulated with "pages < MAX_PAGES")// 2. the last item is visible on the screen (using the "IntersectionObserver")updateItems();setPages((pages)=>pages+1);}else{setHasMore(false);}}});if (node)observer.current.observe(node);},[isLoading,hasMore]);constupdateItems=async ()=>{setIsLoading(true);// simulating asynchronous nature of api (which is the general use case for Infinite Scroll)awaitnewPromise((resolve)=>setTimeout(resolve,1000));setItems((currItems)=>{constlastItem=currItems.length;constupdatedItems=[...currItems];for (leti=1;i<=5;i++){constitem=lastItem+i;updatedItems.push(item);}returnupdatedItems;});setIsLoading(false);};return (<React.Fragment><h1>InfiniteScrollDemo</h1>
{items.map((item,index)=>index+1===items.length?(<Itemreference={lastItemRef}key={index}>{item}</Item>
):(<Itemkey={index}>{item}</Item>
))}{isLoading&&<divclassName="loader"/>}</React.Fragment>
);};