Flipkart / recyclerlistview

High performance listview for React Native and web!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

canChangeSize bug on web

arjendevos opened this issue · comments

commented

We are using React Native Web and we noticed a bug when using Recyclerlistview. It appeared it was rendering all items, this caused the pagina to break and get very slow. So i created a test component and tried to narrow down the problem.

First problem:
When adding no styles, we get this error:

LayoutException: RecyclerListView needs to have a bounded size. Currently height or, width is 0.Consider adding style={{flex:1}} or, fixed dimensions

This is fixed by adding this:

scrollViewProps={{
  contentContainerStyle: {
    paddingTop: 100
  },
}}

This is quite a weird problem.

Second problem:
Recyclerlistview only renders a few items in the DOM but the height of the Recyclerlistview is the height when all items should be there. So for example i have 100 items with a height of 50. Then the Recyclerlistview would have a height of 5000 but it would only render 7 items. You can scroll down to the bottom but no items are appearing.

The solution to this is by adding canChangeSize. But when we do this, it will render all items on load. So i would have 100 items rendered. This is where the virtualization does not work. When we scroll to the bottom, none of the items get removed or added from/to the DOM. This is not a big problem if you have little data but when you have a lot of data the webpage becomes very buggy and slow.

This is my stripped down version of Recyclerlistview:

import React, { useMemo, useState, useEffect } from "react";
import { View, Text, StyleSheet } from "react-native";
import { RecyclerListView, DataProvider, LayoutProvider } from "recyclerlistview"; // Version can be specified in package.json

enum ViewTypes {
  FULL = 0,
  HALF_LEFT = 1,
  HALF_RIGHT = 2,
}

function CustomListview() {
  const _layoutProvider = layoutMaker();
  const dataProvider = useMemo(() => new DataProvider((r1, r2) => r1 !== r2).cloneWithRows(generateArray(4000)), []);

  return (
    <RecyclerListView
      scrollViewProps={{
        contentContainerStyle: {
          paddingTop: 100,
          flex: 1,
        },
      }}
      // canChangeSize
      layoutProvider={_layoutProvider}
      dataProvider={dataProvider}
      rowRenderer={(type, data) => (
        <View style={styles.container}>
          <Text>Data: {data}</Text>
        </View>
      )}
    />
  );
}

export default React.memo(CustomListview);

const layoutMaker = () =>
  new LayoutProvider(
    (index) => {
      return ViewTypes.FULL;
    },
    (type, dim) => {
      switch (type) {
        case ViewTypes.HALF_LEFT:
          dim.width = 1100 / 2;
          dim.height = 160;
          break;
        case ViewTypes.HALF_RIGHT:
          dim.width = 1100 / 2 - 0.001;
          dim.height = 160;
          break;
        case ViewTypes.FULL:
          dim.width = 1100;
          dim.height = 160;
          break;
        default:
          dim.width = 0;
          dim.height = 0;
      }
    }
  );

const generateArray = (n): number[] => {
  let arr = new Array(n);
  for (let i = 0; i < n; i++) {
    arr[i] = i;
  }
  return arr;
};

const styles = StyleSheet.create({
  container: {
    justifyContent: "space-around",
    alignItems: "center",
    flex: 1,
    backgroundColor: "orange",
  },
});

This is what loads in the dom:

Screenshot 2022-08-01 at 15 05 16

This is what is loaded in the dom when using canChangeSize:
Screenshot 2022-08-01 at 15 08 00

You just need to have a parent that matches the size of the window. This problem happens because window is scrollable on web unless you prevent it from doing so.

I'm doing the same in this sample: https://codesandbox.io/s/k54j2zx977?file=/src/index.js