recyclerlistview icon indicating copy to clipboard operation
recyclerlistview copied to clipboard

RecyclerView never removes items which is not visible in window

Open sergeymild opened this issue 3 years ago • 5 comments

I have a thousands of data and when i scroll down i see that rowHasChanged triggers on each item few times and close to end rowHasChanged triggers more times that i have items, which is slow and i never see useEffect's callback which triggers when component did remove. So if i have a complex listItem RecyclerView consume a lot of memory. So that's a point to use recyclerView if it doesn't handle remove and recreate views which out of screen?

sergeymild avatar Jan 29 '22 18:01 sergeymild

I solved this issue by tracking the index of the item that the users is seeing and saying on rowRender to render items that are x index below and y index above.

gustavolsilvano avatar Aug 12 '22 19:08 gustavolsilvano

As it called RecyclerListView it must be done in library, and i as consumer must not thinking about it otherwise it is not a RecyclerListView it is basic listView without any performance optimizations.

sergeymild avatar Aug 15 '22 07:08 sergeymild

@gustavolsilvano Hey gustavo, how did you achieved that?

lucianobracco-geojam avatar Nov 08 '22 23:11 lucianobracco-geojam

I don't understand why this issue doesn't get more attention. This is the entire point of a component like this, and it doesn't do what it is supposed to do.

peterzanetti avatar Jun 21 '23 16:06 peterzanetti

@peterzanetti and anyone else that encounters this issue for the future. I was able to resolve this issue by properly implementing the layout provider as the documentation does not do a proper job of explaining how the recycling works.

Essentially, the recycling depends on a proper layout provider implementation being able to determine dimensions and height/width for a given index item.

  const layout_provider = useMemo(
      () =>
          new LayoutProvider(
              (index) => 0, // This is very important for the recycling to work properly
              (_, dimensions, index) => {
                  // The width is always full width
                  dimensions.width = SCREEN_WIDTH;

                  // Calculate the height based on the type
                  const item = data.current[index].item;
                  if (typeof item == 'string') {
                      dimensions.height = titleHeight;
                  } else {
                      dimensions.height = releaseHeight;
                  }
              }
          ),
      [SCREEN_WIDTH, titleHeight, releaseHeight]
  );

In the snippet above, observe that the first argument to the LayoutProvider aka. the getLayoutTypeForIndex is simply a callback which always returns 0 aka. a fixed value. In my case, this was the problem which was causing the recycling to not work and the view to render / keep all items loaded.

My implementation before would simply return the index itself for this callback which was causing the recycling to not work as the list view thought of each item as a different layout type hence not recyclable. To be honest with you, I don't really know the purpose of having different types or when you would want to use different layout types, but in my case keeping it the same was the best way to go since I only had 2 types of items in my whole list and would return the appropriate dimensions depending on the type.

kartikk221 avatar Jul 20 '23 03:07 kartikk221