fix: skip Fabric SafeAreaView state updates while detached from window#735
Merged
Merged
Conversation
When react-native-screens native-stack covers a screen it detaches the screen from the window. The detached SafeAreaView can then read zero safeAreaInsets and commit a zero-inset Fabric state update for the hidden screen, which shows up as a flash of content under the notch or home indicator on pop-back, plus wasted shadow-tree commits for hidden screens. Skip updateStateIfNecessary while the view has no window, mirroring the provider-side superview guard. didMoveToWindow re-runs the update on reattachment, so inset changes that happen while the screen is hidden still propagate.
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.
Summary
Skip
updateStateIfNecessaryon the FabricSafeAreaViewwhile the view has no window.didMoveToWindowre-runs the update on reattachment, so inset changes that happen while a screen is hidden still propagate.Why: when a react-native-screens native stack pushes a screen, it detaches the covered screen from the window.
didMoveToWindowfires withwindow == nil, and when the nearest provider sits outside the screen,findNearestProvidercan't reach it through the severed superview chain and falls back toself, which reports wrongsafeAreaInsets(in my repro the top inset dropped 116 → 0). That gets committed as Fabric state for the hidden screen: it can briefly render under the notch on pop-back until the corrective commit lands, and pays wasted shadow-tree commits while covered.Instrumented log from the example app (native-stack
Detailsscreen resolving to the root provider; push a second Details, pop back):The Paper implementation already guards this (
findNearestProviderreturns nil andinvalidateSafeAreaInsetsearly-returns), and the Fabric provider got the equivalent guard in #629.Test Plan
Example app on an iPhone 17 simulator (Fabric, RN 0.85, react-native-screens 4.25), Native Stack example, with the
Detailsscreen resolving to the root provider (per-screen provider temporarily removed) to trigger the severed-chain path:window=NILcommit for the detached screen on every push/pop cycle.window=NILcommits, and insets are correct immediately after pop (top: 116, bottom: 34).{78, 62, 20, 62}).window=NILcommits are the reliable evidence either way.