Skip to content

Commit 3f50440

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Gracefully handle negative initialScrollIndex in VirtualizedList_EXPERIMENTAL
Summary: Existing code may pass negative values for `initialScrollIndex`, which the previous implemnentation handled gracefully. Handle the case gracefully in VirtualizedList_EXPERIMENTAL as well. Changelog: [Internal][Fixed] - Gracefully handle negative initialScrollIndex in VirtualizedList_EXPERIMENTAL Reviewed By: rshest Differential Revision: D38183625 fbshipit-source-id: 9aea91c4cf3ce2190d769f34ce728a109efc88d4
1 parent d574ea3 commit 3f50440

File tree

4 files changed

+201
-2
lines changed

4 files changed

+201
-2
lines changed

Libraries/Lists/VirtualizedList_EXPERIMENTAL.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
786786

787787
// The initially rendered cells are retained as part of the
788788
// "scroll-to-top" optimization
789-
if (props.initialScrollIndex == null || props.initialScrollIndex === 0) {
789+
if (props.initialScrollIndex == null || props.initialScrollIndex <= 0) {
790790
const initialRegion = VirtualizedList._initialRenderRegion(props);
791791
renderMask.addCells(initialRegion);
792792
}
@@ -808,7 +808,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
808808

809809
static _initialRenderRegion(props: Props): {first: number, last: number} {
810810
const itemCount = props.getItemCount(props.data);
811-
const scrollIndex = props.initialScrollIndex || 0;
811+
const scrollIndex = Math.max(0, props.initialScrollIndex ?? 0);
812812

813813
return {
814814
first: scrollIndex,

Libraries/Lists/__tests__/VirtualizedList-test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,24 @@ it('unmounts sticky headers moved below viewport', () => {
701701
expect(component).toMatchSnapshot();
702702
});
703703

704+
it('gracefully handles negaitve initialScrollIndex', () => {
705+
const items = generateItems(10);
706+
const ITEM_HEIGHT = 10;
707+
708+
const component = ReactTestRenderer.create(
709+
<VirtualizedList
710+
initialScrollIndex={-1}
711+
initialNumToRender={4}
712+
{...baseItemProps(items)}
713+
{...fixedHeightItemLayoutProps(ITEM_HEIGHT)}
714+
/>,
715+
);
716+
717+
// Existing code assumes we handle this in some way. Do something reasonable
718+
// here.
719+
expect(component).toMatchSnapshot();
720+
});
721+
704722
it('renders offset cells in initial render when initialScrollIndex set', () => {
705723
const items = generateItems(10);
706724
const ITEM_HEIGHT = 10;

Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2714,6 +2714,91 @@ exports[`expands render area by maxToRenderPerBatch on tick 1`] = `
27142714
</RCTScrollView>
27152715
`;
27162716

2717+
exports[`gracefully handles negaitve initialScrollIndex 1`] = `
2718+
<RCTScrollView
2719+
data={
2720+
Array [
2721+
Object {
2722+
"key": 0,
2723+
},
2724+
Object {
2725+
"key": 1,
2726+
},
2727+
Object {
2728+
"key": 2,
2729+
},
2730+
Object {
2731+
"key": 3,
2732+
},
2733+
Object {
2734+
"key": 4,
2735+
},
2736+
Object {
2737+
"key": 5,
2738+
},
2739+
Object {
2740+
"key": 6,
2741+
},
2742+
Object {
2743+
"key": 7,
2744+
},
2745+
Object {
2746+
"key": 8,
2747+
},
2748+
Object {
2749+
"key": 9,
2750+
},
2751+
]
2752+
}
2753+
getItem={[Function]}
2754+
getItemCount={[Function]}
2755+
getItemLayout={[Function]}
2756+
initialNumToRender={4}
2757+
initialScrollIndex={-1}
2758+
onContentSizeChange={[Function]}
2759+
onLayout={[Function]}
2760+
onMomentumScrollBegin={[Function]}
2761+
onMomentumScrollEnd={[Function]}
2762+
onScroll={[Function]}
2763+
onScrollBeginDrag={[Function]}
2764+
onScrollEndDrag={[Function]}
2765+
renderItem={[Function]}
2766+
scrollEventThrottle={50}
2767+
stickyHeaderIndices={Array []}
2768+
>
2769+
<View>
2770+
<View
2771+
style={null}
2772+
>
2773+
<MockCellItem
2774+
value={0}
2775+
/>
2776+
</View>
2777+
<View
2778+
style={null}
2779+
>
2780+
<MockCellItem
2781+
value={1}
2782+
/>
2783+
</View>
2784+
<View
2785+
style={null}
2786+
>
2787+
<MockCellItem
2788+
value={2}
2789+
/>
2790+
</View>
2791+
<View
2792+
style={
2793+
Object {
2794+
"height": 70,
2795+
}
2796+
}
2797+
/>
2798+
</View>
2799+
</RCTScrollView>
2800+
`;
2801+
27172802
exports[`renders a zero-height tail spacer on initial render if getItemLayout not defined 1`] = `
27182803
<RCTScrollView
27192804
data={

Libraries/Lists/__tests__/__snapshots__/VirtualizedList_EXPERIMENTAL-test.js.snap

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3491,6 +3491,102 @@ exports[`expands render area by maxToRenderPerBatch on tick 1`] = `
34913491
</RCTScrollView>
34923492
`;
34933493

3494+
exports[`gracefully handles negaitve initialScrollIndex 1`] = `
3495+
<RCTScrollView
3496+
data={
3497+
Array [
3498+
Object {
3499+
"key": 0,
3500+
},
3501+
Object {
3502+
"key": 1,
3503+
},
3504+
Object {
3505+
"key": 2,
3506+
},
3507+
Object {
3508+
"key": 3,
3509+
},
3510+
Object {
3511+
"key": 4,
3512+
},
3513+
Object {
3514+
"key": 5,
3515+
},
3516+
Object {
3517+
"key": 6,
3518+
},
3519+
Object {
3520+
"key": 7,
3521+
},
3522+
Object {
3523+
"key": 8,
3524+
},
3525+
Object {
3526+
"key": 9,
3527+
},
3528+
]
3529+
}
3530+
getItem={[Function]}
3531+
getItemCount={[Function]}
3532+
getItemLayout={[Function]}
3533+
initialNumToRender={4}
3534+
initialScrollIndex={-1}
3535+
onContentSizeChange={[Function]}
3536+
onLayout={[Function]}
3537+
onMomentumScrollBegin={[Function]}
3538+
onMomentumScrollEnd={[Function]}
3539+
onScroll={[Function]}
3540+
onScrollBeginDrag={[Function]}
3541+
onScrollEndDrag={[Function]}
3542+
renderItem={[Function]}
3543+
scrollEventThrottle={50}
3544+
stickyHeaderIndices={Array []}
3545+
>
3546+
<View>
3547+
<View
3548+
onFocusCapture={[Function]}
3549+
style={null}
3550+
>
3551+
<MockCellItem
3552+
value={0}
3553+
/>
3554+
</View>
3555+
<View
3556+
onFocusCapture={[Function]}
3557+
style={null}
3558+
>
3559+
<MockCellItem
3560+
value={1}
3561+
/>
3562+
</View>
3563+
<View
3564+
onFocusCapture={[Function]}
3565+
style={null}
3566+
>
3567+
<MockCellItem
3568+
value={2}
3569+
/>
3570+
</View>
3571+
<View
3572+
onFocusCapture={[Function]}
3573+
style={null}
3574+
>
3575+
<MockCellItem
3576+
value={3}
3577+
/>
3578+
</View>
3579+
<View
3580+
style={
3581+
Object {
3582+
"height": 60,
3583+
}
3584+
}
3585+
/>
3586+
</View>
3587+
</RCTScrollView>
3588+
`;
3589+
34943590
exports[`renders a zero-height tail spacer on initial render if getItemLayout not defined 1`] = `
34953591
<RCTScrollView
34963592
data={

0 commit comments

Comments
 (0)