// copy form https://github.com/loktar00/react-lazy-load/blob/master/src/LazyLoad.tsx#L2 import { Card } from 'antd'; import React, { Children, Component, createElement, ReactNode, RefObject } from 'react'; import scrollParent from './utils'; type Props = { children: ReactNode; className?: string; elementType?: string; height?: string | number; offset?: string | number; threshold?: number; width?: number | string; onContentVisible?: () => void; }; type State = { visible: boolean; }; export class IntersectionLoad extends Component { static defaultProps = { elementType: 'div', className: '', offset: 0, threshold: 0, width: null, onContentVisible: null, height: null, }; elementObserver: IntersectionObserver | null; wrapper: RefObject | null; constructor(props: Props) { super(props); this.elementObserver = null; this.wrapper = React.createRef(); this.state = { visible: false }; } componentDidMount() { let eventNode = this.getEventNode(); if (eventNode === window) { eventNode = document.body; } setTimeout(() => { const { offset, threshold } = this.props; const options = { rootMargin: typeof offset === 'number' ? `${offset}px` : offset || '0px', threshold: threshold || 0, root: document.body, }; this.elementObserver = new IntersectionObserver(this.lazyLoadHandler, options); const node = this.wrapper?.current; if (node instanceof HTMLElement) { this.elementObserver.observe(node); } }, 200); } shouldComponentUpdate(_: Props, nextState: State) { return nextState.visible; } componentWillUnmount() { const node = this.wrapper?.current; if (node && node instanceof HTMLElement) { this.elementObserver?.unobserve(node); } } getEventNode() { if (!this.wrapper?.current) return document.body; return scrollParent(this.wrapper?.current); } lazyLoadHandler = (entries: IntersectionObserverEntry[]) => { const { onContentVisible } = this.props; const [entry] = entries; const { isIntersecting } = entry; if (isIntersecting) { this.setState({ visible: true }, () => { if (onContentVisible) { onContentVisible(); } }); // Stop observing const node = this.wrapper?.current; if (node && node instanceof HTMLElement) { this.elementObserver?.unobserve(node); } } }; render() { const { children, className, height, width, elementType } = this.props; const { visible } = this.state; const elStyles = { width }; const elClasses = `LazyLoad${visible ? ' is-visible' : ''}${className ? ` ${className}` : ''}`; const componentElementType = elementType || 'div'; return createElement( componentElementType, { className: elClasses, style: elStyles, ref: this.wrapper, }, visible ? ( Children.only(children) ) : ( ), ); } }