private _buildPages()

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,
    };
  }