UNPKG

@times-components/lazy-load

Version:

Use IntersectionObserver to lazy load resources

137 lines (115 loc) 3.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = require("react"); var _propTypes = _interopRequireDefault(require("prop-types")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* eslint-env browser */ class LazyLoad extends _react.Component { constructor(props) { super(props); this.isObserving = false; this.pending = new Set(); this.pendingTimer = null; this.state = { clientHasRendered: false, nodes: new Map() }; this.unobserved = new Set(); this.unobservedTimer = null; this.registerNode = this.registerNode.bind(this); if (typeof window === "undefined" || !("IntersectionObserver" in window)) { return; } this.isObserving = true; const options = { rootMargin: props.rootMargin, threshold: props.threshold }; this.observer = new window.IntersectionObserver(this.handleObservation.bind(this), options); } componentDidMount() { const newState = { clientHasRendered: true }; // eslint-disable-next-line react/no-did-mount-set-state this.setState(newState); } componentWillUnmount() { if (this.observer) { this.observer.disconnect(); } clearTimeout(this.pendingTimer); clearTimeout(this.unobservedTimer); this.pending.clear(); this.unobserved.clear(); } handleObservation(entries) { const threshold = this.props.threshold; const nodes = this.state.nodes; entries.forEach(_ref => { let target = _ref.target, intersectionRatio = _ref.intersectionRatio; if (intersectionRatio >= threshold && !nodes.get(target.id)) { this.pending.add(target); } else if (intersectionRatio < threshold && this.pending.has(target)) { this.pending.delete(target); } }); clearTimeout(this.pendingTimer); if (this.pending.size) { this.pendingTimer = setTimeout(() => { if (!this.pending.size) { return; } this.setState(state => ({ nodes: new Map([...state.nodes, ...[...this.pending].map(n => [n.id, n])]) })); this.pending.clear(); }, 100); } } registerNode(node) { if (!node) { return; } if (!this.observer) { if (this.unobserved.has(node)) { return; } this.unobserved.add(node); clearTimeout(this.unobservedTimer); this.unobservedTimer = setTimeout(() => { this.setState({ nodes: new Map([...this.unobserved].map(n => [n.id, n])) }); this.unobserved.clear(); }, 10); return; } this.observer.observe(node); } render() { const children = this.props.children; const _this$state = this.state, clientHasRendered = _this$state.clientHasRendered, nodes = _this$state.nodes; return children({ clientHasRendered, isObserving: this.isObserving, observed: nodes, registerNode: this.registerNode }); } } LazyLoad.propTypes = { children: _propTypes.default.func.isRequired, rootMargin: _propTypes.default.string, threshold: _propTypes.default.number.isRequired }; LazyLoad.defaultProps = { rootMargin: "0px" }; var _default = LazyLoad; exports.default = _default;