in packages/react/src/components/List/List.tsx [856:975]
private _buildPages(props: IListProps<T>, state: IListState<T>): IListState<T> {
let { renderCount } = props;
const { items, startIndex, getPageHeight } = props;
renderCount = this._getRenderCount(props);
const materializedRect = { ...EMPTY_RECT };
const pages: IPage<T>[] = [];
let itemsPerPage = 1;
let pageTop = 0;
let currentSpacer = null;
const focusedIndex = this._focusedIndex;
const endIndex = startIndex! + renderCount;
const shouldVirtualize = this._shouldVirtualize(props);
// First render is very important to track; when we render cells, we have no idea of estimated page height.
// So we should default to rendering only the first page so that we can get information.
// However if the user provides a measure function, let's just assume they know the right heights.
const isFirstRender = this._estimatedPageHeight === 0 && !getPageHeight;
const allowedRect = this._allowedRect;
for (let itemIndex = startIndex!; itemIndex < endIndex; itemIndex += itemsPerPage) {
const pageSpecification = this._getPageSpecification(itemIndex, allowedRect);
const pageHeight = pageSpecification.height;
const pageData = pageSpecification.data;
const key = pageSpecification.key;
itemsPerPage = pageSpecification.itemCount;
const pageBottom = pageTop + pageHeight - 1;
const isPageRendered =
findIndex(state.pages as IPage<T>[], (page: IPage<T>) => !!page.items && page.startIndex === itemIndex) > -1;
const isPageInAllowedRange = !allowedRect || (pageBottom >= allowedRect.top && pageTop <= allowedRect.bottom!);
const isPageInRequiredRange =
!this._requiredRect || (pageBottom >= this._requiredRect.top && pageTop <= this._requiredRect.bottom!);
const isPageVisible =
(!isFirstRender && (isPageInRequiredRange || (isPageInAllowedRange && isPageRendered))) || !shouldVirtualize;
const isPageFocused = focusedIndex >= itemIndex && focusedIndex < itemIndex + itemsPerPage;
const isFirstPage = itemIndex === startIndex;
// console.log('building page', itemIndex, 'pageTop: ' + pageTop, 'inAllowed: ' +
// isPageInAllowedRange, 'inRequired: ' + isPageInRequiredRange);
// Only render whats visible, focused, or first page,
// or when running in fast rendering mode (not in virtualized mode), we render all current items in pages
if (isPageVisible || isPageFocused || isFirstPage) {
if (currentSpacer) {
pages.push(currentSpacer);
currentSpacer = null;
}
const itemsInPage = Math.min(itemsPerPage, endIndex - itemIndex);
const newPage = this._createPage(
key,
items!.slice(itemIndex, itemIndex + itemsInPage),
itemIndex,
undefined,
undefined,
pageData,
);
newPage.top = pageTop;
newPage.height = pageHeight;
if (this._visibleRect && this._visibleRect.bottom) {
newPage.isVisible = pageBottom >= this._visibleRect.top && pageTop <= this._visibleRect.bottom;
}
pages.push(newPage);
if (isPageInRequiredRange && this._allowedRect) {
_mergeRect(materializedRect, {
top: pageTop,
bottom: pageBottom,
height: pageHeight,
left: allowedRect.left,
right: allowedRect.right,
width: allowedRect.width,
});
}
} else {
if (!currentSpacer) {
currentSpacer = this._createPage(
SPACER_KEY_PREFIX + itemIndex,
undefined,
itemIndex,
0,
undefined,
pageData,
true /*isSpacer*/,
);
}
currentSpacer.height = (currentSpacer.height || 0) + (pageBottom - pageTop) + 1;
currentSpacer.itemCount += itemsPerPage;
}
pageTop += pageBottom - pageTop + 1;
// in virtualized mode, we render need to render first page then break and measure,
// otherwise, we render all items without measurement to make rendering fast
if (isFirstRender && shouldVirtualize) {
break;
}
}
if (currentSpacer) {
currentSpacer.key = SPACER_KEY_PREFIX + 'end';
pages.push(currentSpacer);
}
this._materializedRect = materializedRect;
// console.log('materialized: ', materializedRect);
return {
...state,
pages: pages,
measureVersion: this._measureVersion,
};
}