Skip to content

Commit fb7b4da

Browse files
Unify stale scroll metrics logic
1 parent 13c3b15 commit fb7b4da

File tree

2 files changed

+41
-85
lines changed

2 files changed

+41
-85
lines changed

packages/virtualized-lists/Lists/VirtualizedList.js

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,14 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
462462
this.props.getItemCount(this.props.data) > minIndexForVisible
463463
? VirtualizedList._getItemKey(this.props, minIndexForVisible)
464464
: null,
465-
pendingScrollUpdateCount: 0,
465+
// When we have a non-zero initialScrollIndex, we will receive a
466+
// scroll event later so this will prevent the window from updating
467+
// until we get a valid offset.
468+
pendingScrollUpdateCount:
469+
this.props.initialScrollIndex != null &&
470+
this.props.initialScrollIndex > 0
471+
? 1
472+
: 0,
466473
};
467474
}
468475

@@ -631,6 +638,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
631638
_adjustCellsAroundViewport(
632639
props: Props,
633640
cellsAroundViewport: {first: number, last: number},
641+
pendingScrollUpdateCount: number,
634642
): {first: number, last: number} {
635643
const {data, getItemCount} = props;
636644
const onEndReachedThreshold = onEndReachedThresholdOrDefault(
@@ -662,22 +670,9 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
662670
),
663671
};
664672
} else {
665-
// If we have a positive non-zero initialScrollIndex and run this before we've scrolled,
666-
// we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex.
667-
// So let's wait until we've scrolled the view to the right place. And until then,
668-
// we will trust the initialScrollIndex suggestion.
669-
670-
// Thus, we want to recalculate the windowed render limits if any of the following hold:
671-
// - initialScrollIndex is undefined or is 0
672-
// - initialScrollIndex > 0 AND scrolling is complete
673-
// - initialScrollIndex > 0 AND the end of the list is visible (this handles the case
674-
// where the list is shorter than the visible area)
675-
if (
676-
props.initialScrollIndex != null &&
677-
props.initialScrollIndex > 0 &&
678-
!this._scrollMetrics.offset &&
679-
Math.abs(distanceFromEnd) >= Number.EPSILON
680-
) {
673+
// If we have a pending scroll update, we should not adjust the render window as it
674+
// might override the correct window.
675+
if (pendingScrollUpdateCount > 0) {
681676
return cellsAroundViewport.last >= getItemCount(data)
682677
? VirtualizedList._constrainToItemCount(cellsAroundViewport, props)
683678
: cellsAroundViewport;
@@ -1561,7 +1556,6 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
15611556
onStartReachedThreshold,
15621557
onEndReached,
15631558
onEndReachedThreshold,
1564-
initialScrollIndex,
15651559
} = this.props;
15661560
// If we have any pending scroll updates it means that the scroll metrics
15671561
// are out of date and we should not call any of the edge reached callbacks.
@@ -1620,14 +1614,8 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
16201614
isWithinStartThreshold &&
16211615
this._scrollMetrics.contentLength !== this._sentStartForContentLength
16221616
) {
1623-
// On initial mount when using initialScrollIndex the offset will be 0 initially
1624-
// and will trigger an unexpected onStartReached. To avoid this we can use
1625-
// timestamp to differentiate between the initial scroll metrics and when we actually
1626-
// received the first scroll event.
1627-
if (!initialScrollIndex || this._scrollMetrics.timestamp !== 0) {
1628-
this._sentStartForContentLength = this._scrollMetrics.contentLength;
1629-
onStartReached({distanceFromStart});
1630-
}
1617+
this._sentStartForContentLength = this._scrollMetrics.contentLength;
1618+
onStartReached({distanceFromStart});
16311619
}
16321620

16331621
// If the user scrolls away from the start or end and back again,
@@ -1868,16 +1856,13 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
18681856
};
18691857

18701858
_updateCellsToRender = () => {
1871-
if (this.state.pendingScrollUpdateCount > 0) {
1872-
return;
1873-
}
1874-
18751859
this._updateViewableItems(this.props, this.state.cellsAroundViewport);
18761860

18771861
this.setState((state, props) => {
18781862
const cellsAroundViewport = this._adjustCellsAroundViewport(
18791863
props,
18801864
state.cellsAroundViewport,
1865+
state.pendingScrollUpdateCount,
18811866
);
18821867
const renderMask = VirtualizedList._createRenderMask(
18831868
props,
@@ -2051,6 +2036,11 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
20512036
props: FrameMetricProps,
20522037
cellsAroundViewport: {first: number, last: number},
20532038
) {
2039+
// If we have any pending scroll updates it means that the scroll metrics
2040+
// are out of date and we should not call any of the visibility callbacks.
2041+
if (this.state.pendingScrollUpdateCount > 0) {
2042+
return;
2043+
}
20542044
this._viewabilityTuples.forEach(tuple => {
20552045
tuple.viewabilityHelper.onUpdate(
20562046
props,

packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap

Lines changed: 21 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,45 +1837,12 @@ exports[`adjusts render area with non-zero initialScrollIndex 1`] = `
18371837
/>
18381838
</View>
18391839
<View
1840-
onFocusCapture={[Function]}
1841-
style={null}
1842-
>
1843-
<MockCellItem
1844-
value={15}
1845-
/>
1846-
</View>
1847-
<View
1848-
onFocusCapture={[Function]}
1849-
style={null}
1850-
>
1851-
<MockCellItem
1852-
value={16}
1853-
/>
1854-
</View>
1855-
<View
1856-
onFocusCapture={[Function]}
1857-
style={null}
1858-
>
1859-
<MockCellItem
1860-
value={17}
1861-
/>
1862-
</View>
1863-
<View
1864-
onFocusCapture={[Function]}
1865-
style={null}
1866-
>
1867-
<MockCellItem
1868-
value={18}
1869-
/>
1870-
</View>
1871-
<View
1872-
onFocusCapture={[Function]}
1873-
style={null}
1874-
>
1875-
<MockCellItem
1876-
value={19}
1877-
/>
1878-
</View>
1840+
style={
1841+
Object {
1842+
"height": 50,
1843+
}
1844+
}
1845+
/>
18791846
</View>
18801847
</RCTScrollView>
18811848
`;
@@ -3628,10 +3595,18 @@ exports[`handles maintainVisibleContentPosition 3`] = `
36283595
<View
36293596
style={
36303597
Object {
3631-
"height": 90,
3598+
"height": 80,
36323599
}
36333600
}
36343601
/>
3602+
<View
3603+
onFocusCapture={[Function]}
3604+
style={null}
3605+
>
3606+
<MockCellItem
3607+
value={29}
3608+
/>
3609+
</View>
36353610
<View
36363611
onFocusCapture={[Function]}
36373612
style={null}
@@ -4623,21 +4598,12 @@ exports[`renders new items when data is updated with non-zero initialScrollIndex
46234598
/>
46244599
</View>
46254600
<View
4626-
onFocusCapture={[Function]}
4627-
style={null}
4628-
>
4629-
<MockCellItem
4630-
value={2}
4631-
/>
4632-
</View>
4633-
<View
4634-
onFocusCapture={[Function]}
4635-
style={null}
4636-
>
4637-
<MockCellItem
4638-
value={3}
4639-
/>
4640-
</View>
4601+
style={
4602+
Object {
4603+
"height": 20,
4604+
}
4605+
}
4606+
/>
46414607
</View>
46424608
</RCTScrollView>
46434609
`;

0 commit comments

Comments
 (0)