UNPKG

inferno-window-infinite-loader

Version:

This is a port of the origin library written in React, InfiniteLoader component inspired by react-virtualized but for use with react-window

268 lines (214 loc) 8.39 kB
'use strict'; var inferno = require('inferno'); function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } // Credit: preact-compat - https://github.com/developit/preact-compat :) function shallowDiffers(a, b) { var i; for (i in a) { if (!(i in b)) { return true; } } for (i in b) { if (a[i] !== b[i]) { return true; } } return false; } var PureComponent = /*#__PURE__*/ function (_Component) { _inheritsLoose(PureComponent, _Component); function PureComponent() { return _Component.apply(this, arguments) || this; } var _proto = PureComponent.prototype; _proto.shouldComponentUpdate = function shouldComponentUpdate(props, state) { return shallowDiffers(this.props, props) || shallowDiffers(this.state, state); }; return PureComponent; }(inferno.Component); function isRangeVisible(_ref) { var lastRenderedStartIndex = _ref.lastRenderedStartIndex, lastRenderedStopIndex = _ref.lastRenderedStopIndex, startIndex = _ref.startIndex, stopIndex = _ref.stopIndex; return !(startIndex > lastRenderedStopIndex || stopIndex < lastRenderedStartIndex); } function scanForUnloadedRanges(_ref) { var isItemLoaded = _ref.isItemLoaded, itemCount = _ref.itemCount, minimumBatchSize = _ref.minimumBatchSize, startIndex = _ref.startIndex, stopIndex = _ref.stopIndex; var unloadedRanges = []; var rangeStartIndex = null; var rangeStopIndex = null; for (var _index = startIndex; _index <= stopIndex; _index++) { var loaded = isItemLoaded(_index); if (!loaded) { rangeStopIndex = _index; if (rangeStartIndex === null) { rangeStartIndex = _index; } } else if (rangeStopIndex !== null) { unloadedRanges.push([rangeStartIndex, rangeStopIndex]); rangeStartIndex = rangeStopIndex = null; } } // If :rangeStopIndex is not null it means we haven't ran out of unloaded rows. // Scan forward to try filling our :minimumBatchSize. if (rangeStopIndex !== null) { var potentialStopIndex = Math.min(Math.max(rangeStopIndex, rangeStartIndex + minimumBatchSize - 1), itemCount - 1); for (var _index2 = rangeStopIndex + 1; _index2 <= potentialStopIndex; _index2++) { if (!isItemLoaded(_index2)) { rangeStopIndex = _index2; } else { break; } } unloadedRanges.push([rangeStartIndex, rangeStopIndex]); } // Check to see if our first range ended prematurely. // In this case we should scan backwards to try filling our :minimumBatchSize. if (unloadedRanges.length) { var firstRange = unloadedRanges[0]; while (firstRange[1] - firstRange[0] + 1 < minimumBatchSize && firstRange[0] > 0) { var _index3 = firstRange[0] - 1; if (!isItemLoaded(_index3)) { firstRange[0] = _index3; } else { break; } } } return unloadedRanges; } var InfiniteLoader = /*#__PURE__*/ function (_PureComponent) { _inheritsLoose(InfiniteLoader, _PureComponent); function InfiniteLoader() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _PureComponent.call.apply(_PureComponent, [this].concat(args)) || this; _this._lastRenderedStartIndex = -1; _this._lastRenderedStopIndex = -1; _this._listRef = void 0; _this._memoizedUnloadedRanges = []; _this._onItemsRendered = function (_ref) { var visibleStartIndex = _ref.visibleStartIndex, visibleStopIndex = _ref.visibleStopIndex; if (process.env.NODE_ENV !== 'production') { if (!Number.isInteger(visibleStartIndex) || !Number.isInteger(visibleStopIndex)) { console.warn('Invalid onItemsRendered signature; please refer to InfiniteLoader documentation.'); } if (typeof _this.props.loadMoreRows === 'function') { console.warn('InfiniteLoader "loadMoreRows" prop has been renamed to "loadMoreItems".'); } } _this._lastRenderedStartIndex = visibleStartIndex; _this._lastRenderedStopIndex = visibleStopIndex; _this._ensureRowsLoaded(visibleStartIndex, visibleStopIndex); }; _this._setRef = function (listRef) { _this._listRef = listRef; }; return _this; } var _proto = InfiniteLoader.prototype; _proto.resetloadMoreItemsCache = function resetloadMoreItemsCache(autoReload) { if (autoReload === void 0) { autoReload = false; } this._memoizedUnloadedRanges = []; if (autoReload) { this._ensureRowsLoaded(this._lastRenderedStartIndex, this._lastRenderedStopIndex); } }; _proto.componentDidMount = function componentDidMount() { if (process.env.NODE_ENV !== 'production') { if (this._listRef == null) { console.warn('Invalid list ref; please refer to InfiniteLoader documentation.'); } } }; _proto.render = function render() { var children = this.props.children; return children({ onItemsRendered: this._onItemsRendered, ref: this._setRef }); }; _proto._ensureRowsLoaded = function _ensureRowsLoaded(startIndex, stopIndex) { var _this$props = this.props, isItemLoaded = _this$props.isItemLoaded, itemCount = _this$props.itemCount, _this$props$minimumBa = _this$props.minimumBatchSize, minimumBatchSize = _this$props$minimumBa === void 0 ? 10 : _this$props$minimumBa, _this$props$threshold = _this$props.threshold, threshold = _this$props$threshold === void 0 ? 15 : _this$props$threshold; var unloadedRanges = scanForUnloadedRanges({ isItemLoaded: isItemLoaded, itemCount: itemCount, minimumBatchSize: minimumBatchSize, startIndex: Math.max(0, startIndex - threshold), stopIndex: Math.min(itemCount - 1, stopIndex + threshold) }); // Avoid calling load-rows unless range has changed. // This shouldn't be strictly necsesary, but is maybe nice to do. if (this._memoizedUnloadedRanges.length !== unloadedRanges.length || this._memoizedUnloadedRanges.find(function (_ref2, index) { var startIndex = _ref2[0], stopIndex = _ref2[1]; return unloadedRanges[index][0] !== startIndex || unloadedRanges[index][1] !== stopIndex; })) { this._memoizedUnloadedRanges = unloadedRanges; this._loadUnloadedRanges(unloadedRanges); } }; _proto._loadUnloadedRanges = function _loadUnloadedRanges(unloadedRanges) { var _this2 = this; // loadMoreRows was renamed to loadMoreItems in v1.0.3; will be removed in v2.0 var loadMoreItems = this.props.loadMoreItems || this.props.loadMoreRows; unloadedRanges.forEach(function (_ref3) { var startIndex = _ref3[0], stopIndex = _ref3[1]; var promise = loadMoreItems(startIndex, stopIndex); if (promise != null) { promise.then(function () { // Refresh the visible rows if any of them have just been loaded. // Otherwise they will remain in their unloaded visual state. if (isRangeVisible({ lastRenderedStartIndex: _this2._lastRenderedStartIndex, lastRenderedStopIndex: _this2._lastRenderedStopIndex, startIndex: startIndex, stopIndex: stopIndex })) { // Handle an unmount while promises are still in flight. if (_this2._listRef == null) { return; } // Resize cached row sizes for VariableSizeList, // otherwise just re-render the list. if (typeof _this2._listRef.resetAfterIndex === 'function') { _this2._listRef.resetAfterIndex(startIndex, true); } else { // HACK reset temporarily cached item styles to force PureComponent to re-render. // This is pretty gross, but I'm okay with it for now. // Don't judge me. if (typeof _this2._listRef._getItemStyleCache === 'function') { _this2._listRef._getItemStyleCache(-1); } _this2._listRef.forceUpdate(); } } }); } }); }; return InfiniteLoader; }(PureComponent); module.exports = InfiniteLoader;