import React from 'react'; export interface IInfiniteScrollProps { loadMore: () => Promise; hasNextPage: boolean; parentNode: HTMLElement; loader: React.ReactNode; isReverse: boolean; threshold: number; } export interface IInfiniteScrollState { isLoadingNext: boolean; } let offset = 0; class InfiniteScroll extends React.Component { static defaultProps = { isReverse: false, threshold: 350, }; constructor(props: IInfiniteScrollProps) { super(props); this.state = { isLoadingNext: false, }; } componentDidMount() { this.props.parentNode.addEventListener('scroll', this.onScroll); } componentWillUnmount() { this.props.parentNode.removeEventListener('scroll', this.onScroll); } render() { const { children, hasNextPage, loader, isReverse } = this.props; return ( <> {hasNextPage && isReverse && loader} {children} {hasNextPage && !isReverse && loader} ); } private onScroll = async () => { const { parentNode, loadMore, threshold, hasNextPage, isReverse } = this.props; offset = parentNode.scrollTop - threshold; if (this.state.isLoadingNext || !hasNextPage) { return; } const oldScrollHeight = parentNode.scrollHeight; const shouldLoadMore = offset <= 0; if (!shouldLoadMore) { return; } this.setState({ isLoadingNext: true, }); await loadMore(); if (isReverse) { parentNode.scrollTop = parentNode.scrollHeight - oldScrollHeight + threshold + offset; } this.setState({ isLoadingNext: false, }); }; } export default InfiniteScroll;