SectionList (and probably VirtualizedList/FlatList) fails to batch row renders on re-renders
See original GitHub issueIs this a bug report?
Yes
Have you read the Contributing Guidelines?
Yes
Environment
react-native -v
: react-native-cli: 2.0.1 react-native: 0.48.3node -v
: v8.5.0npm -v
: 5.3.0yarn --version
: 1.0.2
Then, specify:
- Target Platform: iOS, Android
- Development Operating System: macOS 10.12.6
- Build tools: n/a
Steps to Reproduce
- Create a
SectionList
(I expect it’s the same forFlatList
andVirtualizedList
too) with a large number of items – several hundred. - After it has rendered, trigger a re-render of the SectionList by changing its data. I do this by applying a filter to the data.
Expected Behavior
The initial render of the SectionList works well for me. My understanding is: when SectionList is first rendered, it renders a minimal number of items (according to initialNumToRender
) and then releases the JS thread to allow user interaction with the page. It then continues to render off-screen rows in batches. Every second or so it will render a batch (of size determined by maxToRenderPerBatch
) and then release the JS thread again. It continues this loop until it has filled the window large enough to satisfy the windowSize
prop. In my application, this works out to a window of around 70 rows with the default value of windowSize=21
. This is a Good Thing because it means that when a user starts scrolling down, the window provides a buffer of offscreen rows that are ready to be displayed.
So that’s all good. The issue I’m having is when a user filters the list. My app provides a button which applies a filter to the list by some condition. When the SectionList
re-renders after this button is pressed, I would expect the SectionList
to only render initialNumToRender
rows, and then release the JS thread, and then incrementally re-populate the window using the same procedure as in the initial render.
Actual Behavior
However, what actually happens is that SectionList re-renders every row in the window at once, locking up the JS thread until they have all re-rendered. In practical terms, this makes my application appear to lag a lot, as it takes several seconds to render all 70 rows. So my question is: why does SectionList re-render the whole window before releasing the JS thread? Is this a bug? Is there a way I can get it to only render initialNumToRender
rows on a re-render, and then re-populate the window gradually for a smoother user experience?
Reproducible Demo
I tried to create a demo but couldn’t get snack to work very well.
UPDATE: I got a demo working : https://snack.expo.io/H1osQ8fiW
I’ve used a FlatList since it’s simpler than a SectionList, but the same problem is there. I’ve set updateCellsBatchingPeriod to 4 seconds to make it clear when the batched updates are happening.
- When the app loads, open the console. When a row is rendered, a log message appears. Every 4 seconds, 10ish messages should appear, corresponding to a batch of offscreen rows being rendered.
- Don’t scroll up or down – you don’t need to. Wait until new messages stop appearing – this will take about 30 seconds due to the large updateCellsBatchingPeriod I’ve set. It will end up rendering about 70 rows.
- Now press the “Toggle data” button at the bottom of the page. This will toggle the data set being displayed. You will see a noticeable stutter in the UI, and then the [A1, A2, A3…] values will be replaced with [B1, B2, B3…] values.
- Look at the console when you press the button. Even though there is only space on the screen for <10 rows, you’ll see that all 70 rows are immediately re-rendered, with none of the batching that the first render displayed.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:4
- Comments:14
Top GitHub Comments
I can confirm this is a bug. This is happening to me too!
This is still an issue for us.