fix(ios): force-apply all view props on a component view's first updateProps (blank view after react-freeze recreation) - #1484
Closed
rlods wants to merge 1 commit into
Conversation
…teProps Fabric can mount a component view with a Props object whose isDirty flags were already consumed by a different view instance (view recreated from an unchanged ShadowNode, e.g. react-freeze; or a recycled view remounted for another node). updateProps would then apply nothing, leaving the fresh HybridView unconfigured and hybridRef never firing. Track _didApplyInitialProps per view instance, force-apply everything on the first updateProps, and reset the flag in prepareForRecycle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Author
|
Closing as duplicate of #1479, which handles never-set props ( |
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.
Symptom
On iOS (new architecture), a Nitro view renders permanently blank after navigating away from its screen and coming back, when the app uses
react-native-screenswithenableFreeze(true)(react-freeze / Suspense). The native view is laid out correctly (size, background) but no props are ever applied to the fresh hybrid, andhybridRefnever fires — so JS keeps a ref to the dead old hybrid and imperative calls silently no-op.Originally reproduced and analyzed with
RiveViewfromrive-app/rive-nitro-react-native— full write-up in rive-app/rive-nitro-react-native#365 (opened against the generated file committed there; this PR is the durable fix in the template, as suggested in that PR's description).Root cause
When a screen is frozen, Fabric deletes its native views; on return it recreates them from the same, unchanged ShadowNodes — calling
updateProps:oldProps:on the brand-new component view with the same cachedPropsobject as before.The generated
updatePropsguards every prop withisDirtyand, after applying it, mutates the shared props object (newViewProps.<prop>.isDirty = false;viaconst_cast). Those flags were already consumed by the previous view instance, so on recreationupdatePropsapplies nothing:hybridRefnever re-fires, so JS still holds the ref to the old, dead hybrid.Nothing ever marks the props dirty again unless a prop changes identity on the JS side, so the view stays broken forever.
The same "consumed flags on a shared Props object" mechanism also affects recycled views being remounted for a different ShadowNode — the stale-props family of #1050.
Fix
In
SwiftHybridViewManager.ts(the template forHybrid*Component.mm):BOOL _didApplyInitialPropson the component view;hybridRef) on the firstupdatePropsof each view instance, keeping theisDirtyfast path for all subsequent updates;prepareForRecycle, so a recycled view force-applies the next node's props on remount.First-ever mounts are unaffected (all flags are dirty there anyway). Regenerated the committed
react-native-nitro-testfixtures.We've been running the equivalent patch (minus the recycle part) in production (several Rive scenes behind frozen tab/stack screens) and it fixes the blank-view repro deterministically.
Android's JNI state updater has the same consumed-
isDirtypattern in theory, but we could not reproduce the bug there and fixing it needs a JNI signature change (updateViewProps(view, state, forceApply)), so this PR is iOS-only — happy to follow up on Android if you think it's worth it.Repro
react-native-screens,enableFreeze(true)hybridRefnever fired; only a prop identity change revives it🤖 Generated with Claude Code