Skip to content

How to NOT re-render list rows when scrolling? #74

@michael-land

Description

@michael-land

Assume I have the following settings:

The container height: 400
The row height: 40

const virtual = useVirtual({
  size: 1000,
  parentRef,
  overscan: 20,
  estimateSize: useCallback(() => 40, [size]),
})

It seems that the container re-renders every visible row every time new row appears. This behavior maybe intentional but what if my row is heavyweight and the cost to re-render them is not trivial?

What I want to do is re-render only when the last row is visible.

In the above setup, I should see re-render happen once when i scroll to the 30th element, and insert next 20 element since overscan is 20.


Edit:

After play around with the source code, I see that setRange(prevRange => calculateRange(latestRef.current, prevRange)) actually cause the re-render every time index change.

I changed the if condition from

  if (!prevRange || prevRange.start !== start || prevRange.end !== end) {
    return {
      start: start,
      end: end
    };
  }

to


  if (!prevRange ||
    Math.abs(start - prevRange.start) > overscan - 1 ||
    Math.abs(end - prevRange.end) > overscan - 1
    ) {
    return {
      start: start,
      end: end
    };
  }

It reduce re-render from 999 to 50 when the data size is 1000 and overscan is 20.

Maybe we can allow developer to pass custom calculateRange function if they need to optimize performance? or improve calculateRange when overscan is used?

https://github.com/tannerlinsley/react-virtual/blob/master/src/index.js#L77

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions