UNPKG

react-limited-infinite-scroll

Version:
138 lines (116 loc) 4.82 kB
import React, { Component } from 'react' import PropTypes from 'prop-types' export default class LimitedInfiniteScroll extends Component { static propTypes = { limit: PropTypes.number, pageStart: PropTypes.number, threshold: PropTypes.number, hasMore: PropTypes.bool, autoLoad: PropTypes.bool, useWindow: PropTypes.bool, loadNext: PropTypes.func.isRequired, spinLoader: PropTypes.element, mannualLoader: PropTypes.element, noMore: PropTypes.element } static defaultProps = { limit: 5, pageStart: 0, threshold: 200, hasMore: false, autoLoad: true, useWindow: true, spinLoader: <div style={{textAlign: 'center', fontSize: 20, lineHeight: 1.5, paddingTop: 20, paddingBottom: 20, clear: 'both'}}>Loading...</div>, mannualLoader: <div style={{textAlign: 'center', clear: 'both', display: 'inline-block'}}><span style={{fontSize: 20, lineHeight: 1.5, marginTop: 20, marginBottom: 20, display: 'inline-block', color: '#88899a', border: '1px solid #88899a', borderTopLeftRadius: 3, borderTopRightRadius: 3, borderBottomRightRadius: 3, borderBottomLeftRadius: 3, padding: '10px 20px', cursor: 'pointer'}}>Load More</span></div>, noMore: null } state = { loading: false } calcTop = (element) => { if (!element) { return 0 } return element.offsetTop + this.calcTop(element.offsetParent) } scrollHandler = () => { let offset const el = this.selfComponent if (this.props.useWindow) { let scrollTop = window.pageYOffset !== undefined ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop offset = this.calcTop(el) + el.offsetHeight - scrollTop - window.innerHeight } else { offset = el.scrollHeight - el.parentNode.scrollTop - el.parentNode.clientHeight } if (offset < Number(this.props.threshold)) { this.detachScrollEvent() if (typeof this.props.loadNext === 'function') { this.setState({ loading: true }) this.props.loadNext(this.page += 1) } } } attachScrollEvent = () => { if (!this.props.hasMore) { return } const scrollEl = this.props.useWindow ? window : this.selfComponent.parentNode scrollEl.addEventListener('scroll', this.scrollHandler, false) scrollEl.addEventListener('resize', this.scrollHandler, false) if (this.props.autoLoad && !this.autoLoaded) { this.autoLoaded = true this.scrollHandler() } } detachScrollEvent = () => { const scrollEl = this.props.useWindow ? window : this.selfComponent.parentNode scrollEl.removeEventListener('scroll', this.scrollHandler, false) scrollEl.removeEventListener('resize', this.scrollHandler, false) } componentWillMount () { this.page = this.props.pageStart this.autoLoaded = false } componentDidMount () { this.attachScrollEvent() } componentWillUpdate (nextProps, nextState) { if (this.props.children.length < nextProps.children.length) { this.setState({ loading: false }) } } componentDidUpdate (prevProps, prevState) { if ((!this.props.limit || this.page < this.props.limit) && this.props.children.length > prevProps.children.length) { setTimeout(() => { this.attachScrollEvent() }, 0) } } componentWillUnmount () { this.detachScrollEvent() } render () { const {limit, pageStart, threshold, hasMore, autoLoad, useWindow, loadNext, spinLoader, mannualLoader, noMore, children, ...props} = this.props const cloneMannualLoader = React.cloneElement(mannualLoader, { onClick: () => { this.setState({ loading: true }) loadNext(this.page += 1) } }) props.ref = node => { this.selfComponent = node } return ( <div {...props}> {children} {this.state.loading && hasMore && <div style={{textAlign: 'center'}}>{spinLoader}</div>} {!this.state.loading && hasMore && limit > 0 && this.page >= limit && <div style={{textAlign: 'center'}}>{cloneMannualLoader}</div>} {!hasMore && noMore} </div> ) } }