Skip to content

Commit b2f871a

Browse files
motiz88facebook-github-bot
authored andcommitted
Fix crash with SectionList.scrollToLocation and private property munging
Summary: Changelog: [General][Fixed] - Remove illegal private property access in VirtualizedSectionList.scrollToLocation `VirtualizedSectionList.scrollToLocation` internally uses `VirtualizedList`'s `_getFrameMetricsApprox` method. This method is private by convention (since it's `_`-prefixed), but under certain build setups this is also enforced at runtime, so using `scrollToLocation` can throw an error. Here, we rename this internal method to `__getFrameMetricsApprox` (adding another leading underscore) which opts it out of being treated as private, while still communicating that it's not part of the public API. We also delete the Flow error suppression that masked this issue. For reference: This convention for private methods (including the double-underscore opt out) has its roots in Facebook's pre-Babel [JSTransform](https://github.com/facebookarchive/jstransform/blob/master/visitors/es6-class-visitors.js) compiler and is implemented in Flow as [`munge_underscores=true`](https://flow.org/en/docs/config/options/#toc-munge-underscores-boolean). Reviewed By: yungsters Differential Revision: D33982339 fbshipit-source-id: 498563c59d42549c94fe90d363677d6d3ea35d2d
1 parent 9cd4334 commit b2f871a

File tree

2 files changed

+18
-21
lines changed

2 files changed

+18
-21
lines changed

Libraries/Lists/VirtualizedList.js

+17-19
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
384384
scrollToEnd(params?: ?{animated?: ?boolean, ...}) {
385385
const animated = params ? params.animated : true;
386386
const veryLast = this.props.getItemCount(this.props.data) - 1;
387-
const frame = this._getFrameMetricsApprox(veryLast);
387+
const frame = this.__getFrameMetricsApprox(veryLast);
388388
const offset = Math.max(
389389
0,
390390
frame.offset +
@@ -458,7 +458,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
458458
});
459459
return;
460460
}
461-
const frame = this._getFrameMetricsApprox(index);
461+
const frame = this.__getFrameMetricsApprox(index);
462462
const offset =
463463
Math.max(
464464
0,
@@ -950,8 +950,8 @@ class VirtualizedList extends React.PureComponent<Props, State> {
950950
// See if there are any sticky headers in the virtualized space that we need to render.
951951
for (let ii = firstAfterInitial - 1; ii > lastInitialIndex; ii--) {
952952
if (stickyIndicesFromProps.has(ii + stickyOffset)) {
953-
const initBlock = this._getFrameMetricsApprox(lastInitialIndex);
954-
const stickyBlock = this._getFrameMetricsApprox(ii);
953+
const initBlock = this.__getFrameMetricsApprox(lastInitialIndex);
954+
const stickyBlock = this.__getFrameMetricsApprox(ii);
955955
const leadSpace =
956956
stickyBlock.offset -
957957
initBlock.offset -
@@ -968,7 +968,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
968968
inversionStyle,
969969
);
970970
const trailSpace =
971-
this._getFrameMetricsApprox(first).offset -
971+
this.__getFrameMetricsApprox(first).offset -
972972
(stickyBlock.offset + stickyBlock.length);
973973
cells.push(
974974
<View key="$sticky_trail" style={{[spacerKey]: trailSpace}} />,
@@ -979,9 +979,9 @@ class VirtualizedList extends React.PureComponent<Props, State> {
979979
}
980980
}
981981
if (!insertedStickySpacer) {
982-
const initBlock = this._getFrameMetricsApprox(lastInitialIndex);
982+
const initBlock = this.__getFrameMetricsApprox(lastInitialIndex);
983983
const firstSpace =
984-
this._getFrameMetricsApprox(first).offset -
984+
this.__getFrameMetricsApprox(first).offset -
985985
(initBlock.offset + initBlock.length);
986986
cells.push(
987987
<View key="$lead_spacer" style={{[spacerKey]: firstSpace}} />,
@@ -1005,14 +1005,14 @@ class VirtualizedList extends React.PureComponent<Props, State> {
10051005
this._hasWarned.keys = true;
10061006
}
10071007
if (!isVirtualizationDisabled && last < itemCount - 1) {
1008-
const lastFrame = this._getFrameMetricsApprox(last);
1008+
const lastFrame = this.__getFrameMetricsApprox(last);
10091009
// Without getItemLayout, we limit our tail spacer to the _highestMeasuredFrameIndex to
10101010
// prevent the user for hyperscrolling into un-measured area because otherwise content will
10111011
// likely jump around as it renders in above the viewport.
10121012
const end = this.props.getItemLayout
10131013
? itemCount - 1
10141014
: Math.min(itemCount - 1, this._highestMeasuredFrameIndex);
1015-
const endFrame = this._getFrameMetricsApprox(end);
1015+
const endFrame = this.__getFrameMetricsApprox(end);
10161016
const tailSpacerLength =
10171017
endFrame.offset +
10181018
endFrame.length -
@@ -1419,16 +1419,16 @@ class VirtualizedList extends React.PureComponent<Props, State> {
14191419
const framesInLayout = [];
14201420
const itemCount = this.props.getItemCount(this.props.data);
14211421
for (let ii = 0; ii < itemCount; ii++) {
1422-
const frame = this._getFrameMetricsApprox(ii);
1422+
const frame = this.__getFrameMetricsApprox(ii);
14231423
/* $FlowFixMe[prop-missing] (>=0.68.0 site=react_native_fb) This comment
14241424
* suppresses an error found when Flow v0.68 was deployed. To see the
14251425
* error delete this comment and run Flow. */
14261426
if (frame.inLayout) {
14271427
framesInLayout.push(frame);
14281428
}
14291429
}
1430-
const windowTop = this._getFrameMetricsApprox(this.state.first).offset;
1431-
const frameLast = this._getFrameMetricsApprox(this.state.last);
1430+
const windowTop = this.__getFrameMetricsApprox(this.state.first).offset;
1431+
const frameLast = this.__getFrameMetricsApprox(this.state.last);
14321432
const windowLen = frameLast.offset + frameLast.length - windowTop;
14331433
const visTop = this._scrollMetrics.offset;
14341434
const visLen = this._scrollMetrics.visibleLength;
@@ -1642,15 +1642,15 @@ class VirtualizedList extends React.PureComponent<Props, State> {
16421642
// Mark as high priority if we're close to the start of the first item
16431643
// But only if there are items before the first rendered item
16441644
if (first > 0) {
1645-
const distTop = offset - this._getFrameMetricsApprox(first).offset;
1645+
const distTop = offset - this.__getFrameMetricsApprox(first).offset;
16461646
hiPri =
16471647
hiPri || distTop < 0 || (velocity < -2 && distTop < scrollingThreshold);
16481648
}
16491649
// Mark as high priority if we're close to the end of the last item
16501650
// But only if there are items after the last rendered item
16511651
if (last < itemCount - 1) {
16521652
const distBottom =
1653-
this._getFrameMetricsApprox(last).offset - (offset + visibleLength);
1653+
this.__getFrameMetricsApprox(last).offset - (offset + visibleLength);
16541654
hiPri =
16551655
hiPri ||
16561656
distBottom < 0 ||
@@ -1752,7 +1752,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
17521752
maxToRenderPerBatchOrDefault(this.props.maxToRenderPerBatch),
17531753
windowSizeOrDefault(this.props.windowSize),
17541754
state,
1755-
this._getFrameMetricsApprox,
1755+
this.__getFrameMetricsApprox,
17561756
this._scrollMetrics,
17571757
);
17581758
}
@@ -1815,13 +1815,11 @@ class VirtualizedList extends React.PureComponent<Props, State> {
18151815
return {index, item, key: this._keyExtractor(item, index), isViewable};
18161816
};
18171817

1818-
_getFrameMetricsApprox = (
1819-
index: number,
1820-
): {
1818+
__getFrameMetricsApprox: (index: number) => {
18211819
length: number,
18221820
offset: number,
18231821
...
1824-
} => {
1822+
} = index => {
18251823
const frame = this._getFrameMetrics(index);
18261824
if (frame && frame.index === index) {
18271825
// check for invalid frames due to row re-ordering

Libraries/Lists/VirtualizedSectionList.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ class VirtualizedSectionList<
137137
return;
138138
}
139139
if (params.itemIndex > 0 && this.props.stickySectionHeadersEnabled) {
140-
// $FlowFixMe[prop-missing] Cannot access private property
141-
const frame = this._listRef._getFrameMetricsApprox(
140+
const frame = this._listRef.__getFrameMetricsApprox(
142141
index - params.itemIndex,
143142
);
144143
viewOffset += frame.length;

0 commit comments

Comments
 (0)