Skip to content

Compounding FlatList delays when React rendering exceeds 1.66ms per-item (60hz) #7237

@NickGerleman

Description

@NickGerleman

Example:

The below example adds a log-point inside of VirtualizedList._onScroll to show when we are responding to scroll messages received from native. This example is intentionally synthetically slow.

We can see from logging that we may continually process scroll messages, long after scrolling has stopped. This is because scroll events are being produced faster than the VirtualizedList can respond with, and not being coalesced.

Lacks.coalescing.mp4

Steps to repro:

  1. Create a FlatList/SectionList with windowSize equal to 1, and many expensive components to render. E.g.
  // Stick this in your item render function to block the JS thread
  const fib = n  => (n < 2) ? 2 : fib(n-2) + fib(n-1);
  fib(30);
  1. Set windowSize to 1
  2. Place logpoint in VirtualizedList.onScroll with `VirtualizedList handled scroll message at (${Date.now()}ms)` or similar
  3. Scroll

Background:

FlatList through VirtualizedList listens to the topScroll native event. React Native provides platform guarantees this is delivered once-per-frame. This is implemented (for UWP and Android) by sending the latest scroll position at the end of a frame.

While this throttles the rate of delivered events, it does not guarantee JS is pumping events fast enough to prevent stale data. If JS rendering exceeds the time of a single native frame, the next render batch will be processing input from a frame behind. This delay is added for every stale message.

By default a single render batch is limited to 10 items. In fast scroll scenarios, each frame can be a different set of items. This means me need to effectively render 10 items per frame from JS to avoid these sorts of delays.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions