Skip to content

fix(layout): skip measurement while web container is hidden - #2523

Open
HuuNguyen312 wants to merge 1 commit into
Shopify:mainfrom
HuuNguyen312:fix/web-hidden-container-measurement
Open

HuuNguyen312 wants to merge 1 commit into
Shopify:mainfrom
HuuNguyen312:fix/web-hidden-container-measurement

Conversation

@HuuNguyen312

Copy link
Copy Markdown

Description

Fixes #2522

On web, when a FlashList is mounted inside a container that becomes hidden (display: none, e.g. an inactive screen/column kept mounted), every DOM size reads as 0. If the list re-renders while hidden (data update, parent state change), the layout effects still run and:

  1. measureParentSize returns a 0 x 0 window.
  2. measureItemLayout returns height: 0 for every rendered item, overwriting the real measured heights.
  3. The height average window (last 5 samples) drops to ~0, so every unmeasured item is also estimated at ~0.

With all layouts collapsed to y = 0, height = 0, getVisibleLayouts returns the entire data set as engaged, and the list mounts every item at once. In our chat app (~6,000 messages, inverted list) this froze the app on logout, when the chat screen is hidden but still mounted. Debug output captured at that moment:

engaged 0 5686 count 5687 data 6384 window {"width":0,"height":0}
measured 517 measuredZero 517
0:y=0,h=0 | 1:y=0,h=0 | 2:y=0,h=0 | ...

Fix

  • Add isViewHidden(view) to measureLayout.web.ts: the container is hidden when both clientWidth and clientHeight are 0. The native implementation always returns false, so native behavior is unchanged.
  • In RecyclerView, skip the container-measurement and item-measurement layout effects while the container is hidden, keeping the last valid layouts.
  • While hidden, record a 0 x 0 container size so the existing onLayout size check sees a change once the container is shown again and triggers a fresh measurement.

Reviewers’ hat-rack 🎩

  • On web, render a long list (thousands of items) inside a container, toggle the container to display: none, then update data while hidden. Before: every item renders. After: no extra items render.
  • Show the container again: the list re-measures and renders normally at the same position.
  • Native: no behavior change (isViewHidden always returns false).
  • Unit tests added for isViewHidden (src/__tests__/measureLayout.web.test.ts). yarn test and yarn type-check pass; ESLint is clean on the changed files.

On web, a list inside a display:none container reads every size as 0.
Measuring then overwrote real item heights with 0, so the engaged range
covered the whole data set and every item rendered at once (e.g. ~6000
chat messages on logout).

Skip container and item measurement while the container is hidden and
record a zero container size so onLayout re-measures once it is shown.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Web] FlashList renders every item when it re-renders inside a hidden (display: none) container

1 participant