diff --git a/Libraries/Lists/CellRenderMask.js b/Libraries/Lists/CellRenderMask.js index 786ae7b00bad42..15ce117dbe638d 100644 --- a/Libraries/Lists/CellRenderMask.js +++ b/Libraries/Lists/CellRenderMask.js @@ -110,6 +110,10 @@ export class CellRenderMask { ); } + numCells(): number { + return this._numCells; + } + equals(other: CellRenderMask): boolean { return ( this._numCells === other._numCells && diff --git a/Libraries/Lists/VirtualizeUtils.js b/Libraries/Lists/VirtualizeUtils.js index 11dfd8cc20365b..09d448ae285f50 100644 --- a/Libraries/Lists/VirtualizeUtils.js +++ b/Libraries/Lists/VirtualizeUtils.js @@ -92,7 +92,6 @@ export function computeWindowedRenderLimits( prev: { first: number, last: number, - ... }, getFrameMetricsApprox: (index: number) => { length: number, @@ -109,7 +108,6 @@ export function computeWindowedRenderLimits( ): { first: number, last: number, - ... } { const itemCount = getItemCount(data); if (itemCount === 0) { diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index c411032c269c38..66e94e7bdcf71c 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -40,7 +40,10 @@ import { VirtualizedListContextProvider, type ChildListState, type ListDebugInfo, -} from './VirtualizedListContext.js'; +} from './VirtualizedListContext'; + +import {CellRenderMask} from './CellRenderMask'; +import clamp from '../Utilities/clamp'; type Item = any; @@ -309,8 +312,8 @@ let _usedIndexForKey = false; let _keylessItemComponentName: string = ''; type State = { - first: number, - last: number, + renderMask: CellRenderMask, + cellsAroundViewport: {first: number, last: number}, }; /** @@ -348,6 +351,19 @@ function windowSizeOrDefault(windowSize: ?number) { return windowSize ?? 21; } +function findLastWhere( + arr: $ReadOnlyArray, + predicate: (element: T) => boolean, +): T | null { + for (let i = arr.length - 1; i >= 0; i--) { + if (predicate(arr[i])) { + return arr[i]; + } + } + + return null; +} + /** * Base implementation for the more convenient [``](https://reactnative.dev/docs/flatlist.html) * and [``](https://reactnative.dev/docs/sectionlist.html) components, which are also better @@ -690,6 +706,11 @@ class VirtualizedList extends React.PureComponent { 'VirtualizedList: The windowSize prop must be present and set to a value greater than 0.', ); + invariant( + props.getItemCount, + 'VirtualizedList: The "getItemCount" prop must be provided', + ); + this._fillRateHelper = new FillRateHelper(this._getFrameMetrics); this._updateCellsToRenderBatcher = new Batchinator( this._updateCellsToRender, @@ -711,14 +732,11 @@ class VirtualizedList extends React.PureComponent { }); } - let initialState = { - first: this.props.initialScrollIndex || 0, - last: - Math.min( - this.props.getItemCount(this.props.data), - (this.props.initialScrollIndex || 0) + - initialNumToRenderOrDefault(this.props.initialNumToRender), - ) - 1, + const initialRenderRegion = VirtualizedList._initialRenderRegion(props); + + let initialState: State = { + cellsAroundViewport: initialRenderRegion, + renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion), }; if (this._isNestedWithSameOrientation()) { @@ -733,6 +751,166 @@ class VirtualizedList extends React.PureComponent { this.state = initialState; } + static _createRenderMask( + props: Props, + cellsAroundViewport: {first: number, last: number}, + ): CellRenderMask { + const itemCount = props.getItemCount(props.data); + + invariant( + cellsAroundViewport.first >= 0 && + cellsAroundViewport.last >= cellsAroundViewport.first - 1 && + cellsAroundViewport.last < itemCount, + `Invalid cells around viewport "[${cellsAroundViewport.first}, ${cellsAroundViewport.last}]" was passed to VirtualizedList._createRenderMask`, + ); + + const renderMask = new CellRenderMask(itemCount); + + if (itemCount > 0) { + renderMask.addCells(cellsAroundViewport); + + // The initially rendered cells are retained as part of the + // "scroll-to-top" optimization + if (props.initialScrollIndex == null || props.initialScrollIndex === 0) { + const initialRegion = VirtualizedList._initialRenderRegion(props); + renderMask.addCells(initialRegion); + } + + // The layout coordinates of sticker headers may be off-screen while the + // actual header is on-screen. Keep the most recent before the viewport + // rendered, even if its layout coordinates are not in viewport. + const stickyIndicesSet = new Set(props.stickyHeaderIndices); + VirtualizedList._ensureClosestStickyHeader( + props, + stickyIndicesSet, + renderMask, + cellsAroundViewport.first, + ); + } + + return renderMask; + } + + static _initialRenderRegion(props: Props): {first: number, last: number} { + const itemCount = props.getItemCount(props.data); + const scrollIndex = props.initialScrollIndex || 0; + + return { + first: scrollIndex, + last: + Math.min( + itemCount, + scrollIndex + initialNumToRenderOrDefault(props.initialNumToRender), + ) - 1, + }; + } + + static _ensureClosestStickyHeader( + props: Props, + stickyIndicesSet: Set, + renderMask: CellRenderMask, + cellIdx: number, + ) { + const stickyOffset = props.ListHeaderComponent ? 1 : 0; + + for (let itemIdx = cellIdx - 1; itemIdx >= 0; itemIdx--) { + if (stickyIndicesSet.has(itemIdx + stickyOffset)) { + renderMask.addCells({first: itemIdx, last: itemIdx}); + break; + } + } + } + + _adjustCellsAroundViewport( + props: Props, + cellsAroundViewport: {first: number, last: number}, + ): {first: number, last: number} { + const {data, getItemCount} = props; + const onEndReachedThreshold = onEndReachedThresholdOrDefault( + props.onEndReachedThreshold, + ); + this._updateViewableItems(data); + + const {contentLength, offset, visibleLength} = this._scrollMetrics; + + // Wait until the scroll view metrics have been set up. And until then, + // we will trust the initialNumToRender suggestion + if (visibleLength <= 0 || contentLength <= 0) { + return cellsAroundViewport; + } + + let newCellsAroundViewport: {first: number, last: number}; + if (this._isVirtualizationDisabled()) { + const distanceFromEnd = contentLength - visibleLength - offset; + const renderAhead = + distanceFromEnd < onEndReachedThreshold * visibleLength + ? maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch) + : 0; + + newCellsAroundViewport = { + first: 0, + last: Math.min( + this.state.cellsAroundViewport.last + renderAhead, + getItemCount(data) - 1, + ), + }; + } else { + // If we have a non-zero initialScrollIndex and run this before we've scrolled, + // wait until we've scrolled the view to the right place. And until then, + // we will trust the initialScrollIndex suggestion. + if (this.props.initialScrollIndex && !this._scrollMetrics.offset) { + return cellsAroundViewport; + } + + newCellsAroundViewport = computeWindowedRenderLimits( + props.data, + props.getItemCount, + maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch), + windowSizeOrDefault(props.windowSize), + cellsAroundViewport, + this._getFrameMetricsApprox, + this._scrollMetrics, + ); + } + + if (this._nestedChildLists.size > 0) { + // If some cell in the new state has a child list in it, we should only render + // up through that item, so that we give that list a chance to render. + // Otherwise there's churn from multiple child lists mounting and un-mounting + // their items. + + // Will this prevent rendering if the nested list doesn't realize the end? + const childIdx = this._findFirstChildWithMore( + newCellsAroundViewport.first, + newCellsAroundViewport.last, + ); + + newCellsAroundViewport.last = childIdx ?? newCellsAroundViewport.last; + } + + return newCellsAroundViewport; + } + + _findFirstChildWithMore(first: number, last: number): number | null { + for (let ii = first; ii <= last; ii++) { + const cellKeyForIndex = this._indicesToKeys.get(ii); + const childListKeys = + cellKeyForIndex && this._cellKeysToChildListKeys.get(cellKeyForIndex); + if (!childListKeys) { + continue; + } + // For each cell, need to check whether any child list in it has more elements to render + for (let childKey of childListKeys) { + const childList = this._nestedChildLists.get(childKey); + if (childList && childList.ref && childList.ref.hasMore()) { + return ii; + } + } + } + + return null; + } + componentDidMount() { if (this._isNestedWithSameOrientation()) { this.context.registerAsNestedChild({ @@ -753,8 +931,7 @@ class VirtualizedList extends React.PureComponent { this.context.unregisterAsNestedChild({ key: this._getListKey(), state: { - first: this.state.first, - last: this.state.last, + ...this.state, frames: this._frames, }, }); @@ -768,18 +945,21 @@ class VirtualizedList extends React.PureComponent { } static getDerivedStateFromProps(newProps: Props, prevState: State): State { - const {data, getItemCount} = newProps; - const maxToRenderPerBatch = maxToRenderPerBatchOrDefault( - newProps.maxToRenderPerBatch, - ); // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make // sure we're rendering a reasonable range here. + const itemCount = newProps.getItemCount(newProps.data); + if (itemCount === prevState.renderMask.numCells()) { + return prevState; + } + + const constrainedCells = VirtualizedList._constrainToItemCount( + prevState.cellsAroundViewport, + newProps, + ); + return { - first: Math.max( - 0, - Math.min(prevState.first, getItemCount(data) - 1 - maxToRenderPerBatch), - ), - last: Math.max(0, Math.min(prevState.last, getItemCount(data) - 1)), + cellsAroundViewport: prevState.cellsAroundViewport, + renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells), }; } @@ -835,6 +1015,23 @@ class VirtualizedList extends React.PureComponent { } } + static _constrainToItemCount( + cells: {first: number, last: number}, + props: Props, + ): {first: number, last: number} { + const itemCount = props.getItemCount(props.data); + const last = Math.min(itemCount - 1, cells.last); + + const maxToRenderPerBatch = maxToRenderPerBatchOrDefault( + props.maxToRenderPerBatch, + ); + + return { + first: clamp(0, itemCount - 1 - maxToRenderPerBatch, cells.first), + last, + }; + } + _onUpdateSeparators = (keys: Array, newProps: Object) => { keys.forEach(key => { const ref = key != null && this._cellRefs[key]; @@ -885,7 +1082,6 @@ class VirtualizedList extends React.PureComponent { const {ListEmptyComponent, ListFooterComponent, ListHeaderComponent} = this.props; const {data, horizontal} = this.props; - const isVirtualizationDisabled = this._isVirtualizationDisabled(); const inversionStyle = this.props.inverted ? horizontalOrDefault(this.props.horizontal) ? styles.horizontallyInverted @@ -894,6 +1090,8 @@ class VirtualizedList extends React.PureComponent { const cells = []; const stickyIndicesFromProps = new Set(this.props.stickyHeaderIndices); const stickyHeaderIndices = []; + + // 1. Add cell for ListHeaderComponent if (ListHeaderComponent) { if (stickyIndicesFromProps.has(0)) { stickyHeaderIndices.push(0); @@ -923,103 +1121,10 @@ class VirtualizedList extends React.PureComponent { , ); } + + // 2a. Add a cell for ListEmptyComponent if applicable const itemCount = this.props.getItemCount(data); - if (itemCount > 0) { - _usedIndexForKey = false; - _keylessItemComponentName = ''; - const spacerKey = this._getSpacerKey(!horizontal); - const lastInitialIndex = this.props.initialScrollIndex - ? -1 - : initialNumToRenderOrDefault(this.props.initialNumToRender) - 1; - const {first, last} = this.state; - this._pushCells( - cells, - stickyHeaderIndices, - stickyIndicesFromProps, - 0, - lastInitialIndex, - inversionStyle, - ); - const firstAfterInitial = Math.max(lastInitialIndex + 1, first); - if (!isVirtualizationDisabled && first > lastInitialIndex + 1) { - let insertedStickySpacer = false; - if (stickyIndicesFromProps.size > 0) { - const stickyOffset = ListHeaderComponent ? 1 : 0; - // See if there are any sticky headers in the virtualized space that we need to render. - for (let ii = firstAfterInitial - 1; ii > lastInitialIndex; ii--) { - if (stickyIndicesFromProps.has(ii + stickyOffset)) { - const initBlock = this._getFrameMetricsApprox(lastInitialIndex); - const stickyBlock = this._getFrameMetricsApprox(ii); - const leadSpace = - stickyBlock.offset - - initBlock.offset - - (this.props.initialScrollIndex ? 0 : initBlock.length); - cells.push( - , - ); - this._pushCells( - cells, - stickyHeaderIndices, - stickyIndicesFromProps, - ii, - ii, - inversionStyle, - ); - const trailSpace = - this._getFrameMetricsApprox(first).offset - - (stickyBlock.offset + stickyBlock.length); - cells.push( - , - ); - insertedStickySpacer = true; - break; - } - } - } - if (!insertedStickySpacer) { - const initBlock = this._getFrameMetricsApprox(lastInitialIndex); - const firstSpace = - this._getFrameMetricsApprox(first).offset - - (initBlock.offset + initBlock.length); - cells.push( - , - ); - } - } - this._pushCells( - cells, - stickyHeaderIndices, - stickyIndicesFromProps, - firstAfterInitial, - last, - inversionStyle, - ); - if (!this._hasWarned.keys && _usedIndexForKey) { - console.warn( - 'VirtualizedList: missing keys for items, make sure to specify a key or id property on each ' + - 'item or provide a custom keyExtractor.', - _keylessItemComponentName, - ); - this._hasWarned.keys = true; - } - if (!isVirtualizationDisabled && last < itemCount - 1) { - const lastFrame = this._getFrameMetricsApprox(last); - // Without getItemLayout, we limit our tail spacer to the _highestMeasuredFrameIndex to - // prevent the user for hyperscrolling into un-measured area because otherwise content will - // likely jump around as it renders in above the viewport. - const end = this.props.getItemLayout - ? itemCount - 1 - : Math.min(itemCount - 1, this._highestMeasuredFrameIndex); - const endFrame = this._getFrameMetricsApprox(end); - const tailSpacerLength = - endFrame.offset + - endFrame.length - - (lastFrame.offset + lastFrame.length); - cells.push( - , - ); - } - } else if (ListEmptyComponent) { + if (itemCount === 0 && ListEmptyComponent) { const element: React.Element = ((React.isValidElement( ListEmptyComponent, ) ? ( @@ -1042,6 +1147,70 @@ class VirtualizedList extends React.PureComponent { }), ); } + + // 2b. Add cells and spacers for each item + if (itemCount > 0) { + _usedIndexForKey = false; + _keylessItemComponentName = ''; + const spacerKey = this._getSpacerKey(!horizontal); + + const renderRegions = this.state.renderMask.enumerateRegions(); + const lastSpacer = findLastWhere(renderRegions, r => r.isSpacer); + + for (const section of renderRegions) { + if (section.isSpacer) { + // Legacy behavior is to avoid spacers when virtualization is + // disabled (including head spacers on initial render). + if (this._isVirtualizationDisabled()) { + continue; + } + + // Without getItemLayout, we limit our tail spacer to the _highestMeasuredFrameIndex to + // prevent the user for hyperscrolling into un-measured area because otherwise content will + // likely jump around as it renders in above the viewport. + const isLastSpacer = section === lastSpacer; + const constrainToMeasured = isLastSpacer && !this.props.getItemLayout; + const last = constrainToMeasured + ? clamp( + section.first - 1, + section.last, + this._highestMeasuredFrameIndex, + ) + : section.last; + + const firstMetrics = this._getFrameMetricsApprox(section.first); + const lastMetrics = this._getFrameMetricsApprox(last); + const spacerSize = + lastMetrics.offset + lastMetrics.length - firstMetrics.offset; + cells.push( + , + ); + } else { + this._pushCells( + cells, + stickyHeaderIndices, + stickyIndicesFromProps, + section.first, + section.last, + inversionStyle, + ); + } + } + + if (!this._hasWarned.keys && _usedIndexForKey) { + console.warn( + 'VirtualizedList: missing keys for items, make sure to specify a key or id property on each ' + + 'item or provide a custom keyExtractor.', + _keylessItemComponentName, + ); + this._hasWarned.keys = true; + } + } + + // 3. Add cell for ListFooterComponent if (ListFooterComponent) { const element = React.isValidElement(ListFooterComponent) ? ( ListFooterComponent @@ -1068,6 +1237,8 @@ class VirtualizedList extends React.PureComponent { , ); } + + // 4. Render the ScrollView const scrollProps = { ...this.props, onContentSizeChange: this._onContentSizeChange, @@ -1090,8 +1261,7 @@ class VirtualizedList extends React.PureComponent { : this.props.style, }; - this._hasMore = - this.state.last < this.props.getItemCount(this.props.data) - 1; + this._hasMore = this.state.cellsAroundViewport.last < itemCount - 1; const innerRet = ( { _computeBlankness() { this._fillRateHelper.computeBlankness( this.props, - this.state, + this.state.cellsAroundViewport, this._scrollMetrics, ); } @@ -1425,8 +1595,12 @@ class VirtualizedList extends React.PureComponent { framesInLayout.push(frame); } } - const windowTop = this._getFrameMetricsApprox(this.state.first).offset; - const frameLast = this._getFrameMetricsApprox(this.state.last); + const windowTop = this._getFrameMetricsApprox( + this.state.cellsAroundViewport.first, + ).offset; + const frameLast = this._getFrameMetricsApprox( + this.state.cellsAroundViewport.last, + ); const windowLen = frameLast.offset + frameLast.length - windowTop; const visTop = this._scrollMetrics.offset; const visLen = this._scrollMetrics.visibleLength; @@ -1501,7 +1675,7 @@ class VirtualizedList extends React.PureComponent { onEndReachedThreshold != null ? onEndReachedThreshold * visibleLength : 2; if ( onEndReached && - this.state.last === getItemCount(data) - 1 && + this.state.cellsAroundViewport.last === getItemCount(data) - 1 && distanceFromEnd < threshold && this._scrollMetrics.contentLength !== this._sentEndForContentLength ) { @@ -1629,7 +1803,7 @@ class VirtualizedList extends React.PureComponent { }; _scheduleCellsToRenderUpdate() { - const {first, last} = this.state; + const {first, last} = this.state.cellsAroundViewport; const {offset, visibleLength, velocity} = this._scrollMetrics; const itemCount = this.props.getItemCount(this.props.data); let hiPri = false; @@ -1717,93 +1891,25 @@ class VirtualizedList extends React.PureComponent { }; _updateCellsToRender = () => { - const { - data, - getItemCount, - onEndReachedThreshold: _onEndReachedThreshold, - } = this.props; - const onEndReachedThreshold = onEndReachedThresholdOrDefault( - _onEndReachedThreshold, - ); - const isVirtualizationDisabled = this._isVirtualizationDisabled(); - this._updateViewableItems(data); - if (!data) { - return; - } - this.setState(state => { - let newState; - const {contentLength, offset, visibleLength} = this._scrollMetrics; - if (!isVirtualizationDisabled) { - // If we run this with bogus data, we'll force-render window {first: 0, last: 0}, - // and wipe out the initialNumToRender rendered elements. - // So let's wait until the scroll view metrics have been set up. And until then, - // we will trust the initialNumToRender suggestion - if (visibleLength > 0 && contentLength > 0) { - // If we have a non-zero initialScrollIndex and run this before we've scrolled, - // we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex. - // So let's wait until we've scrolled the view to the right place. And until then, - // we will trust the initialScrollIndex suggestion. - if (!this.props.initialScrollIndex || this._scrollMetrics.offset) { - newState = computeWindowedRenderLimits( - this.props.data, - this.props.getItemCount, - maxToRenderPerBatchOrDefault(this.props.maxToRenderPerBatch), - windowSizeOrDefault(this.props.windowSize), - state, - this._getFrameMetricsApprox, - this._scrollMetrics, - ); - } - } - } else { - const distanceFromEnd = contentLength - visibleLength - offset; - const renderAhead = - distanceFromEnd < onEndReachedThreshold * visibleLength - ? maxToRenderPerBatchOrDefault(this.props.maxToRenderPerBatch) - : 0; - newState = { - first: 0, - last: Math.min(state.last + renderAhead, getItemCount(data) - 1), - }; - } - if (newState && this._nestedChildLists.size > 0) { - const newFirst = newState.first; - const newLast = newState.last; - // If some cell in the new state has a child list in it, we should only render - // up through that item, so that we give that list a chance to render. - // Otherwise there's churn from multiple child lists mounting and un-mounting - // their items. - for (let ii = newFirst; ii <= newLast; ii++) { - const cellKeyForIndex = this._indicesToKeys.get(ii); - const childListKeys = - cellKeyForIndex && - this._cellKeysToChildListKeys.get(cellKeyForIndex); - if (!childListKeys) { - continue; - } - let someChildHasMore = false; - // For each cell, need to check whether any child list in it has more elements to render - for (let childKey of childListKeys) { - const childList = this._nestedChildLists.get(childKey); - if (childList && childList.ref && childList.ref.hasMore()) { - someChildHasMore = true; - break; - } - } - if (someChildHasMore) { - newState.last = ii; - break; - } - } - } + this.setState((state, props) => { + const cellsAroundViewport = this._adjustCellsAroundViewport( + props, + state.cellsAroundViewport, + ); + const renderMask = VirtualizedList._createRenderMask( + props, + cellsAroundViewport, + ); + if ( - newState != null && - newState.first === state.first && - newState.last === state.last + cellsAroundViewport.first === state.cellsAroundViewport.first && + cellsAroundViewport.last === state.cellsAroundViewport.last && + renderMask.equals(state.renderMask) ) { - newState = null; + return null; } - return newState; + + return {cellsAroundViewport, renderMask}; }); }; @@ -1875,7 +1981,7 @@ class VirtualizedList extends React.PureComponent { this._getFrameMetrics, this._createViewToken, tuple.onViewableItemsChanged, - this.state, + this.state.cellsAroundViewport, ); }); } diff --git a/Libraries/Lists/__tests__/VirtualizedList-test.js b/Libraries/Lists/__tests__/VirtualizedList-test.js index b2093ce07c1b10..26223e43fe3beb 100644 --- a/Libraries/Lists/__tests__/VirtualizedList-test.js +++ b/Libraries/Lists/__tests__/VirtualizedList-test.js @@ -965,13 +965,12 @@ it('renders no spacers up to initialScrollIndex on first render when virtualizat ); }); - // There should be no spacers present in an offset initial render with - // virtualiztion disabled. Only initialNumToRender items starting at - // initialScrollIndex. + // We should render initialNumToRender items with no spacers on initial render + // when virtualization is disabled expect(component).toMatchSnapshot(); }); -it('expands first in viewport to render up to maxToRenderPerBatch on initial render', () => { +it('renders initialNumToRender when initialScrollIndex is offset', () => { const items = generateItems(10); const ITEM_HEIGHT = 10; @@ -988,9 +987,7 @@ it('expands first in viewport to render up to maxToRenderPerBatch on initial ren ); }); - // When virtualization is disabled we may render items before initialItemIndex - // if initialItemIndex + initialNumToRender < maToRenderPerBatch. Expect cells - // 0-3 to be rendered in this example, even though initialScrollIndex is 4. + // We should render initialNumToRender items starting at initialScrollIndex. expect(component).toMatchSnapshot(); }); diff --git a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap index ad93703101b2ad..0784444ad79f4d 100644 --- a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap +++ b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap @@ -850,10 +850,8 @@ exports[`VirtualizedList keeps sticky headers above viewport visualized 1`] = ` Array [ 0, 2, - 4, - 7, - 10, - 13, + 5, + 8, ] } windowSize={1} @@ -870,7 +868,7 @@ exports[`VirtualizedList keeps sticky headers above viewport visualized 1`] = ` @@ -879,53 +877,16 @@ exports[`VirtualizedList keeps sticky headers above viewport visualized 1`] = ` > - - - - - - - - - - - - - - - @@ -1993,45 +1954,10 @@ exports[`discards intitial render if initialScrollIndex != 0 1`] = ` - - - - - - - - - - - - - - - @@ -2399,33 +2325,12 @@ exports[`does not over-render when there is less than initialNumToRender cells 1 > - - - - - - - - - - - + style={ + Object { + "height": 40, + } + } + /> @@ -2602,113 +2507,6 @@ exports[`eventually renders all items when virtualization disabled 1`] = ` `; -exports[`expands first in viewport to render up to maxToRenderPerBatch on initial render 1`] = ` - - - - - - - - - - - - - - - - - - - - - - - -`; - exports[`expands render area by maxToRenderPerBatch on tick 1`] = ` + + + + + +`; + +exports[`renders initialNumToRender when initialScrollIndex is offset 1`] = ` + + + @@ -3138,6 +3008,13 @@ exports[`renders initialNumToRender cells when virtualization disabled 1`] = ` value={5} /> + `; @@ -3377,33 +3254,12 @@ exports[`renders offset cells in initial render when initialScrollIndex set 1`] > - - - - - - - - - - - + style={ + Object { + "height": 40, + } + } + /> @@ -3635,7 +3491,7 @@ exports[`renders tail spacer up to last measured with irregular layout when getI @@ -4405,45 +4261,10 @@ exports[`retains intitial render if initialScrollIndex == 0 1`] = ` - - - - - - - - - - - - - - -