petyosi / react-virtuoso

The most powerful virtual list component for React
https://virtuoso.dev
MIT License
5.25k stars 301 forks source link

⚡️ Performance improvement: minimize Layout, Update Layout Tree, Recalculate Style #515

Closed codingedgar closed 2 years ago

codingedgar commented 2 years ago

First of all, fantastic library ✨

Second, this is not a bug. I guess more of a performance improvement, fully available to contribute tho 👍.

Describe the bug Currently, mounting Virtuoso causes a lot of layout/reflow (for more information here is a list of what forces layout/reflow)

I used contain to minimize the Layout / Reflow effect, to realize the event listeners resize/scroll are added to the window and not to a ref inside the Virtuoso tree, rendering contain useless.

There's also the use of both ResizeObserver and resize event listeners. It would be an improvement to figure out how to use only ResizeObserver if possible (I assume there's a pretty good reason to use both).

I also happen to have multiple Virtuoso instances, so sharing the ResizeObserver could be another good improvement, being by providing one externally or using a third-party library to use the same instance indirectly like @react-hook/resize-observer

Reproduction Any environment with Virtuoso would do. (But I can make an example if required)

To Reproduce Steps to reproduce the behaviour:

  1. Go to any env with Virtuoso
  2. Take a snapshot with the Performance inspector in the Chrome Dev Tools
  3. See all the Layout / Reflow

Expected behavior

Screenshots I will add them ASAP

Desktop (please complete the following information):

Additional context I have a pretty crowded UI, with a side pane that mounts Virtuoso in the middle of an animation, where any Layout / Reflow degrades the performance of the animation tremendously, dropping FPS to 7.

Maybe this is a bit extreme, but in my wildest dreams, I aim to mount a Virtuoso component the closest to read-only mode causing 0 Layout / Reflow and enabling its full capabilities later.

petyosi commented 2 years ago

I'm more than happy to accept a performance-improvement PR on the matter. Few notes that might help:

Measuring element dimensions and tracking scroll location is how the dynamic heights work - and this triggers a reflow. I am not seeing a possibility for a radical improvement here, but I would be delighted to be wrong.

Reducing the resize observer instances: In its regular setup, a component instance creates two: one for the viewport and one for tracking the item sizes. You can get additional ones if you have a Header or a Footer. Unless you have dozens of virtual lists resizing at the same time, chasing that optimization might not be worth it. Here's some interesting comment on the matter.

Some additional context: throughout the years, the Virtuoso list has found its niche for use cases like chat lists and feed lists, where people deal with the complexity of inverted scrolling, dynamic heights, items resizing, etc. Those scenarios usually don't involve more than one, maybe two, active scrollable containers at any given moment. I am very hesitant to restructure the size measuring setup (one of the most complex parts of the code) unless it brings significant performance improvements even for a single instance.