Skip to content

Commit

Permalink
Fix onStartReached not called in some cases
Browse files Browse the repository at this point in the history
  • Loading branch information
janicduplessis committed Jul 27, 2024
1 parent 904e950 commit 2ee37d8
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,87 @@
diff --git a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
index e338d90..70a59bf 100644
index e338d90..238989f 100644
--- a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
+++ b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
@@ -1219,7 +1219,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
@@ -89,6 +89,7 @@ type State = {
firstVisibleItemKey: ?string,
// When > 0 the scroll position available in JS is considered stale and should not be used.
pendingScrollUpdateCount: number,
+ lastItemCount: number,
};

function getScrollingThreshold(threshold: number, visibleLength: number) {
@@ -404,12 +405,13 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {

const minIndexForVisible =
this.props.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
+ const itemCount = this.props.getItemCount(this.props.data);

this.state = {
cellsAroundViewport: initialRenderRegion,
renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion),
firstVisibleItemKey:
- this.props.getItemCount(this.props.data) > minIndexForVisible
+ itemCount > minIndexForVisible
? VirtualizedList._getItemKey(this.props, minIndexForVisible)
: null,
// When we have a non-zero initialScrollIndex, we will receive a
@@ -420,6 +422,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
this.props.initialScrollIndex > 0
? 1
: 0,
+ lastItemCount: itemCount,
};
}

@@ -701,16 +704,15 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
// 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()) {
+ if (itemCount === prevState.renderMask.numCells() && itemCount === prevState.lastItemCount) {
return prevState;
}
-
let maintainVisibleContentPositionAdjustment: ?number = null;
const prevFirstVisibleItemKey = prevState.firstVisibleItemKey;
const minIndexForVisible =
newProps.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
const newFirstVisibleItemKey =
- newProps.getItemCount(newProps.data) > minIndexForVisible
+ itemCount > minIndexForVisible
? VirtualizedList._getItemKey(newProps, minIndexForVisible)
: null;
if (
@@ -758,6 +760,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
maintainVisibleContentPositionAdjustment != null
? prevState.pendingScrollUpdateCount + 1
: prevState.pendingScrollUpdateCount,
+ lastItemCount: itemCount,
};
}

@@ -1159,7 +1162,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
}
}

- componentDidUpdate(prevProps: Props) {
+ componentDidUpdate(prevProps: Props, prevState: State) {
const {data, extraData} = this.props;
if (data !== prevProps.data || extraData !== prevProps.extraData) {
// clear the viewableIndices cache to also trigger
@@ -1181,6 +1184,11 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
if (hiPriInProgress) {
this._hiPriInProgress = false;
}
+
+ if (this.state.cellsAroundViewport.first !== prevState.cellsAroundViewport.first ||
+ this.state.cellsAroundViewport.last !== prevState.cellsAroundViewport.last) {
+ this._maybeCallOnEdgeReached();
+ }
}

_cellRefs: {[string]: null | CellRenderer<any>} = {};
@@ -1219,7 +1227,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
zoomScale: 1,
};
_scrollRef: ?React.ElementRef<any> = null;
Expand All @@ -11,7 +90,7 @@ index e338d90..70a59bf 100644
_sentEndForContentLength = 0;
_updateCellsToRenderBatcher: Batchinator;
_viewabilityTuples: Array<ViewabilityHelperCallbackTuple> = [];
@@ -1550,16 +1550,16 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
@@ -1550,16 +1558,16 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
onStartReached != null &&
this.state.cellsAroundViewport.first === 0 &&
isWithinStartThreshold &&
Expand Down
150 changes: 144 additions & 6 deletions patches/react-native-web+0.19.12+005+osr-improvement.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
index b05da08..80aea85 100644
index bede95b..2aef4c6 100644
--- a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
+++ b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
@@ -332,7 +332,7 @@ class VirtualizedList extends StateSafePureComponent {
Expand All @@ -11,7 +11,75 @@ index b05da08..80aea85 100644
this._sentEndForContentLength = 0;
this._totalCellLength = 0;
this._totalCellsMeasured = 0;
@@ -1397,8 +1397,8 @@ class VirtualizedList extends StateSafePureComponent {
@@ -684,16 +684,18 @@ class VirtualizedList extends StateSafePureComponent {
});
}
}
+ var itemCount = this.props.getItemCount(this.props.data);
var initialRenderRegion = VirtualizedList._initialRenderRegion(_props);
var minIndexForVisible = (_this$props$maintainV = (_this$props$maintainV2 = this.props.maintainVisibleContentPosition) == null ? void 0 : _this$props$maintainV2.minIndexForVisible) !== null && _this$props$maintainV !== void 0 ? _this$props$maintainV : 0;
this.state = {
cellsAroundViewport: initialRenderRegion,
renderMask: VirtualizedList._createRenderMask(_props, initialRenderRegion),
- firstVisibleItemKey: this.props.getItemCount(this.props.data) > minIndexForVisible ? VirtualizedList._getItemKey(this.props, minIndexForVisible) : null,
+ firstVisibleItemKey: itemCount > minIndexForVisible ? VirtualizedList._getItemKey(this.props, minIndexForVisible) : null,
// When we have a non-zero initialScrollIndex, we will receive a
// scroll event later so this will prevent the window from updating
// until we get a valid offset.
- pendingScrollUpdateCount: this.props.initialScrollIndex != null && this.props.initialScrollIndex > 0 ? 1 : 0
+ pendingScrollUpdateCount: this.props.initialScrollIndex != null && this.props.initialScrollIndex > 0 ? 1 : 0,
+ lastItemCount: itemCount
};

// REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller.
@@ -919,13 +921,13 @@ class VirtualizedList extends StateSafePureComponent {
// 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.
var itemCount = newProps.getItemCount(newProps.data);
- if (itemCount === prevState.renderMask.numCells()) {
+ if (itemCount === prevState.renderMask.numCells() && itemCount === prevState.lastItemCount) {
return prevState;
}
var maintainVisibleContentPositionAdjustment = null;
var prevFirstVisibleItemKey = prevState.firstVisibleItemKey;
var minIndexForVisible = (_newProps$maintainVis = (_newProps$maintainVis2 = newProps.maintainVisibleContentPosition) == null ? void 0 : _newProps$maintainVis2.minIndexForVisible) !== null && _newProps$maintainVis !== void 0 ? _newProps$maintainVis : 0;
- var newFirstVisibleItemKey = newProps.getItemCount(newProps.data) > minIndexForVisible ? VirtualizedList._getItemKey(newProps, minIndexForVisible) : null;
+ var newFirstVisibleItemKey = itemCount > minIndexForVisible ? VirtualizedList._getItemKey(newProps, minIndexForVisible) : null;
if (newProps.maintainVisibleContentPosition != null && prevFirstVisibleItemKey != null && newFirstVisibleItemKey != null) {
if (newFirstVisibleItemKey !== prevFirstVisibleItemKey) {
// Fast path if items were added at the start of the list.
@@ -944,7 +946,8 @@ class VirtualizedList extends StateSafePureComponent {
cellsAroundViewport: constrainedCells,
renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells),
firstVisibleItemKey: newFirstVisibleItemKey,
- pendingScrollUpdateCount: maintainVisibleContentPositionAdjustment != null ? prevState.pendingScrollUpdateCount + 1 : prevState.pendingScrollUpdateCount
+ pendingScrollUpdateCount: maintainVisibleContentPositionAdjustment != null ? prevState.pendingScrollUpdateCount + 1 : prevState.pendingScrollUpdateCount,
+ lastItemCount: itemCount
};
}
_pushCells(cells, stickyHeaderIndices, stickyIndicesFromProps, first, last, inversionStyle) {
@@ -1220,7 +1223,7 @@ class VirtualizedList extends StateSafePureComponent {
return ret;
}
}
- componentDidUpdate(prevProps) {
+ componentDidUpdate(prevProps, prevState) {
var _this$props7 = this.props,
data = _this$props7.data,
extraData = _this$props7.extraData;
@@ -1244,6 +1247,11 @@ class VirtualizedList extends StateSafePureComponent {
if (hiPriInProgress) {
this._hiPriInProgress = false;
}
+
+ if (this.state.cellsAroundViewport.first !== prevState.cellsAroundViewport.first ||
+ this.state.cellsAroundViewport.last !== prevState.cellsAroundViewport.last) {
+ this._maybeCallOnEdgeReached();
+ }
}

// Used for preventing scrollToIndex from being called multiple times for initialScrollIndex
@@ -1407,8 +1415,8 @@ class VirtualizedList extends StateSafePureComponent {
// Next check if the user just scrolled within the start threshold
// and call onStartReached only once for a given content length,
// and only if onEndReached is not being executed
Expand All @@ -22,7 +90,7 @@ index b05da08..80aea85 100644
onStartReached({
distanceFromStart
});
@@ -1407,7 +1407,7 @@ class VirtualizedList extends StateSafePureComponent {
@@ -1417,7 +1425,7 @@ class VirtualizedList extends StateSafePureComponent {
// If the user scrolls away from the start or end and back again,
// cause onStartReached or onEndReached to be triggered again
else {
Expand All @@ -32,10 +100,80 @@ index b05da08..80aea85 100644
}
}
diff --git a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
index 459f017..799a6ee 100644
index 459f017..d20115c 100644
--- a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
+++ b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
@@ -1325,7 +1325,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
@@ -79,6 +79,7 @@ type State = {
firstVisibleItemKey: ?string,
// When > 0 the scroll position available in JS is considered stale and should not be used.
pendingScrollUpdateCount: number,
+ lastItemCount: number,
};

/**
@@ -453,12 +454,13 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {

const minIndexForVisible =
this.props.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
+ const itemCount = this.props.getItemCount(this.props.data);

this.state = {
cellsAroundViewport: initialRenderRegion,
renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion),
firstVisibleItemKey:
- this.props.getItemCount(this.props.data) > minIndexForVisible
+ itemCount > minIndexForVisible
? VirtualizedList._getItemKey(this.props, minIndexForVisible)
: null,
// When we have a non-zero initialScrollIndex, we will receive a
@@ -469,6 +471,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
this.props.initialScrollIndex > 0
? 1
: 0,
+ lastItemCount: itemCount,
};

// REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller.
@@ -809,16 +812,15 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
// 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()) {
+ if (itemCount === prevState.renderMask.numCells() && itemCount === prevState.lastItemCount) {
return prevState;
}
-
let maintainVisibleContentPositionAdjustment: ?number = null;
const prevFirstVisibleItemKey = prevState.firstVisibleItemKey;
const minIndexForVisible =
newProps.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
const newFirstVisibleItemKey =
- newProps.getItemCount(newProps.data) > minIndexForVisible
+ itemCount > minIndexForVisible
? VirtualizedList._getItemKey(newProps, minIndexForVisible)
: null;
if (
@@ -866,6 +868,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
maintainVisibleContentPositionAdjustment != null
? prevState.pendingScrollUpdateCount + 1
: prevState.pendingScrollUpdateCount,
+ lastItemCount: itemCount,
};
}

@@ -1285,6 +1288,11 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
if (hiPriInProgress) {
this._hiPriInProgress = false;
}
+
+ if (this.state.cellsAroundViewport.first !== prevState.cellsAroundViewport.first ||
+ this.state.cellsAroundViewport.last !== prevState.cellsAroundViewport.last) {
+ this._maybeCallOnEdgeReached();
+ }
}

_averageCellLength = 0;
@@ -1325,7 +1333,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
zoomScale: 1,
};
_scrollRef: ?React.ElementRef<any> = null;
Expand All @@ -44,7 +182,7 @@ index 459f017..799a6ee 100644
_sentEndForContentLength = 0;
_totalCellLength = 0;
_totalCellsMeasured = 0;
@@ -1675,18 +1675,18 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
@@ -1675,18 +1683,18 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
onStartReached != null &&
this.state.cellsAroundViewport.first === 0 &&
isWithinStartThreshold &&
Expand Down

0 comments on commit 2ee37d8

Please sign in to comment.