How to stop calling next on infinite scroll when scroll goes on top?

Viewed 36

I'm using infinite-scroll on my project. The problem is that when I scroll to top of the window, next function will be called and a request will be sent for fetching new data. While it should call next when I scroll to bottom of the list.

Here's the use case of InfiniteScroll:

 <InfiniteScroll dataLength={notificationList.length} 
                 next={this.fetchMoreData} 
                 hasMore={this.state.hasMore} 
                 loader={ <div className={'text-center'}>{Utils.i18n('loadingList', true)}</div>}> {notificationList.length > 0 && notificationList.map((item, index) => { return ( <div key={item.id} name={"scroll-to-element-" + item.id} className={"notification-wrap"}>
     <div className={"row"}>
       <div className={"col-auto"}>
         <h4 className={"title"}> {item.title} </h4>
       </div>
       <div className={"col-auto mr-auto"}>
         <span className={"date"}> {item.createdAt} </span>
       </div>
     </div>
     <div className={"description"}>
       <blockquote> {item.description} </blockquote>
     </div>
   </div> ); })} 
</InfiniteScroll> 
{notificationList.length === 0 && !notificationListLoading&& 
 <div className={"text-center my-4"}> {Utils.i18n('noData', true)} </div> }

and fetchMoreData:

  fetchMoreData = () => {
        if (this.props.notificationSettingReducer.notificationsList) {
            if (this.state.page < this.props.notificationSettingReducer.notificationsList.totalPages) {
                this.setState({
                    page: this.state.page + 1
                }, () => {
                    this.getNotification();
                });
            }
            if (this.state.page === this.props.notificationSettingReducer.notificationsList.totalPages) {
                this.setState({hasMore: false});
            }
        }
    };

It calls next function on both bottom and top. How can I stop InfiniteScroll from calling next and fetching new data when scroll to top or window.scrollY == 0?

2 Answers

You can handle this using IntersectionObserver You can add div after list and add an observer on that div. once that div is visible you can call an API.

const useIntersectionObserver = (ref, callback) => {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        callback();
      }
    });
  });

  React.useEffect(() => {
    if (ref && !ref.current) return;
    observer.observe(ref.current);
    return () => observer.unobserve(ref.current);
  }, [ref.current]);
};

const MainExample = () => {
  const ref = React.useRef(null);
  const [state, setState] = React.useState(Array(10).fill(0));
  useIntersectionObserver(ref, () => {
    console.log("Visible");
    setState((prev) => [...prev, ...Array(10).fill(0)]);
  });

  return (
    <div>
      {state.map((_, index) => (<h1 key={index}>Hello {index + 1}</h1>))}
      <div ref={ref} />
    </div>
  );
};
const root = ReactDOM.createRoot(document.getElementById("mail"));
root.render(<MainExample />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="mail"></div>

ScrollY==0

for the top & ScrollY==document.documentElement.scrollHeight - document.documentElement.clientHeight

for the bottom

Related