import RecyclerListView, { RecyclerListViewProps, RecyclerListViewState } from "./RecyclerListView"; export interface ProgressiveListViewProps extends RecyclerListViewProps { maxRenderAhead?: number; renderAheadStep?: number; } /** * This will incremently update renderAhread distance and render the page progressively. */ export default class ProgressiveListView extends RecyclerListView { public static defaultProps = { ...RecyclerListView.defaultProps, maxRenderAhead: Number.MAX_VALUE, renderAheadStep: 300, renderAheadOffset: 0, }; private renderAheadUdpateCallbackId?: number; public componentDidMount(): void { if (super.componentDidMount) { super.componentDidMount(); } this.updateRenderAheadProgessively(this.getCurrentRenderAheadOffset()); } private updateRenderAheadProgessively(newVal: number): void { this.cancelRenderAheadUpdate(); // Cancel any pending callback. this.renderAheadUdpateCallbackId = requestAnimationFrame(() => { if (!this.updateRenderAheadOffset(newVal)) { this.updateRenderAheadProgessively(newVal); } else { this.incrementRenderAhead(); } }); } private incrementRenderAhead(): void { if (this.props.maxRenderAhead && this.props.renderAheadStep) { const layoutManager = this.getVirtualRenderer().getLayoutManager(); const currentRenderAheadOffset = this.getCurrentRenderAheadOffset(); if (layoutManager) { const contentDimension = layoutManager.getContentDimension(); const maxContentSize = this.props.isHorizontal ? contentDimension.width : contentDimension.height; if (currentRenderAheadOffset < maxContentSize && currentRenderAheadOffset < this.props.maxRenderAhead) { const newRenderAheadOffset = currentRenderAheadOffset + this.props.renderAheadStep; this.updateRenderAheadProgessively(newRenderAheadOffset); } } } } private cancelRenderAheadUpdate(): void { if (this.renderAheadUdpateCallbackId) { cancelAnimationFrame(this.renderAheadUdpateCallbackId); } } }