fix(android): use unstable_getBoundingClientRect for synchronous layout measurement on New Architecture#2292
Open
wildseansy wants to merge 1 commit into
Conversation
…ut measurement
On Android New Architecture (RN 0.78+), View.measureLayout() invokes its
callback asynchronously. measureLayout() calls it synchronously and returns
the local layout object before the callback fires, so the result is always
{x:0, y:0, width:0, height:0}.
This causes FlashList to initialize with a window size of 0, so no items
are ever rendered. The onLayout handler detects the 0 and calls layout(),
triggering a re-render — but useLayoutEffect runs measureLayout again with
the same async/0 result, creating an infinite re-render loop that never
resolves.
unstable_getBoundingClientRect() reads directly from the Fabric shadow
tree and is synchronous on New Architecture. Use it in measureLayout when
available, falling back to measureLayoutRelative for Old Architecture where
the method does not exist.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes FlashList rendering nothing on Android New Architecture (RN 0.78+).
Root cause
View.measureLayout()on Android New Architecture invokes its callback asynchronously — it returns before the callback fires.measureLayout()inmeasureLayout.tscalls it, then immediately returns the locallayoutobject, which is still{x:0, y:0, width:0, height:0}.This means
measureParentSize()always returns{width:0, height:0}, sorecyclerViewManager.updateLayoutParams()is called with a window height of 0. FlashList never renders any items.The
onLayoutevent detects that the stored container size (containerViewSizeRef) is 0 and callsrecyclerViewContext.layout()to trigger a re-render — butuseLayoutEffectrunsmeasureLayoutagain with the same async/0 result, creating an infinite re-render loop that never resolves.Fix
unstable_getBoundingClientRect()reads directly from the Fabric shadow tree and is synchronous on New Architecture (RN 0.78+). Use it inmeasureLayoutwhen available, and fall back tomeasureLayoutRelativeon Old Architecture where the method doesn't exist.The commented-out code at the top of
measureLayout()pointed at this same API. This PR restores that intent with proper type safety and an Old Arch fallback.Relationship to #2269
PR #2269 adds an early return when the container measures 0x0 (a different scenario: transient zero measurements during navigation stack transitions on web). Our fix addresses a separate root cause: the measurement itself never returns a non-zero value on Android New Arch. These two fixes are complementary.
Testing
Verified on Android with React Native 0.85 + New Architecture enabled. FlashList renders items correctly after this change. Without it, the list is permanently blank.
Checklist
measureLayoutRelativeon Old Architectureunstable_getBoundingClientRectis not on the publicViewtype — added a localViewWithBoundingClientRecttype cast