react-native-web: Inverted Flatlist(VirtualizedList) with specific conditions has rendering problem.

The problem Flatlist(VirtualizedList) has problem specific conditions in Web This list rendered the wrong range of index items, Sometimes It is rendered again constantly

How to reproduce Simplified test case: https://snack.expo.io/@kunhee_lee/kunhee_lee_test

Steps to reproduce:

  1. Just scroll up the list
  2. If you scroll up to near by 70~80 , you can see the malfunction
  3. this problem is happend when renderitem has numberic height (ex: maybe upper than 40)

Expected behavior react-native-web/packages/react-native-web/src/vendor/reactnative/VirtualizeUtils/VirtualizeUtils.js

...
const leadFactor = 0.5; // Math.max(0, Math.min(1, velocity / 25 + 0.5));

  const fillPreference =
    velocity > 1 ? 'after' : velocity < -1 ? 'before' : 'none';

  const overscanBegin = Math.max(0,visibleBegin - (1 - leadFactor) * overscanLength, );
  const overscanEnd = Math.max(0, visibleEnd + leadFactor * overscanLength);

  const lastItemOffset = getFrameMetricsApprox(itemCount - 1).offset;
  if (lastItemOffset < overscanBegin) {
    // Entire list is before our overscan window
    return {
      first: Math.max(0, itemCount - 1 - maxToRenderPerBatch),
      last: itemCount - 1,
    };
  }
...

leadFactor(0.5) is not suitable value with some conditions this makes the overscanBegin value bigger than 0 so It cause the wrong retern with wrong first, last If you fix this value leadFactor, this matter would is solved I have tried to make correct formula for leadFactor

Environment (include versions). Did this work in previous versions?

  • React Native for Web (version): 0.12.2
  • React (version): 16.9.0
  • Browser: Chrome

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (3 by maintainers)

Most upvoted comments

@azesmway have you updated this to work with “react-native-web”: “0.17.1”? Looks like these changes are already there, but I’m seeing the same issue still.

Hi I found solution easier

node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js

string 653 newState = computeWindowedRenderLimits(_this.props, state, _this._getFrameMetricsApprox, _this._scrollMetrics); newState.first = 0; // <— this change

I reopened that issue. If someone writes a PR for RN that improves compatibility on web without negatively effecting RN, I will help get the review prioritized

@awmiklovic Hi! No problem, here’s the whole file, you can compare.

“react-native-web”: “^0.13.13” PATH: node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js

index.js.zip

Awesome, thank you! Here’s the diff in case anyone else needs it:

index 8659501..da00709 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
@@ -346,6 +346,15 @@ function (_React$PureComponent) {
       velocity: 0,
       visibleLength: 0
     };
+    _this._scrollMetrics2 = {
+      contentLength: 0,
+      dOffset: 0,
+      dt: 10,
+      offset: 0,
+      timestamp: 0,
+      velocity: 0,
+      visibleLength: 0
+    };
     _this._scrollRef = null;
     _this._sentEndForContentLength = 0;
     _this._totalCellLength = 0;
@@ -506,6 +515,13 @@ function (_React$PureComponent) {
       }
 
       _this._scrollMetrics = {
+        contentLength: contentLength,
+        timestamp: timestamp,
+        velocity: velocity,
+        visibleLength: visibleLength
+      };
+
+      _this._scrollMetrics2 = {
         contentLength: contentLength,
         dt: dt,
         dOffset: dOffset,
@@ -1255,7 +1271,7 @@ function (_React$PureComponent) {
         getItemCount = _this$props10.getItemCount,
         onEndReached = _this$props10.onEndReached,
         onEndReachedThreshold = _this$props10.onEndReachedThreshold;
-    var _this$_scrollMetrics2 = this._scrollMetrics,
+    var _this$_scrollMetrics2 = this._scrollMetrics2,
         contentLength = _this$_scrollMetrics2.contentLength,
         visibleLength = _this$_scrollMetrics2.visibleLength,
         offset = _this$_scrollMetrics2.offset;
@@ -1268,7 +1284,7 @@ function (_React$PureComponent) {
     distanceFromEnd < onEndReachedThreshold * visibleLength && (this._hasDataChangedSinceEndReached || this._scrollMetrics.contentLength !== this._sentEndForContentLength)) {
       // Only call onEndReached once for a given dataset + content length.
       this._hasDataChangedSinceEndReached = false;
-      this._sentEndForContentLength = this._scrollMetrics.contentLength;
+      this._sentEndForContentLength = this._scrollMetrics2.contentLength;
       onEndReached({
         distanceFromEnd: distanceFromEnd
       });