[cherry-pick][4.2] Fix commits during the Android draw pass#9123
Merged
bartlomiejbloniarz merged 2 commits intoMar 20, 2026
Merged
Conversation
## Summary Separates the synchronous UI props update logic into its own `applySynchronousUpdates` method. Adds `partitionUpdates` and `shouldUseSynchronousUpdatesInPerformOperations` helpers to support the extracted method. ## Test plan
## Summary This PR intends to solve the most annoying crash that we currently face on Android. The crash is caused by Reanimated calling `ShadowTree::commit` when handling events that were emitted while in the Android drawing pass. Performing a commit can cause other changes queued by React Native to also get applied. This can lead to the view hierarchy being modified, which is not allowed while in the draw pass. To fix this, we have a workaround where if we are in the draw pass, we instead only apply non-layout changes (that can be applied without a ShadowTree commit), and schedule the layout changes to happen when we are outside of the draw call. We want to apply the non-layout updates there to maintain things like transform driven sticky headers. closes #8422 🤞 ## Test plan I added a new Android Draw Pass example, it would also make sense to test the sticky header and other event related examples
Contributor
There was a problem hiding this comment.
Pull request overview
Cherry-picks upstream fixes to prevent Reanimated from committing Fabric ShadowTree updates during the Android draw pass (a known crash scenario), by splitting “layout” vs “non-layout” updates and deferring layout-affecting commits until the next frame. It also refactors synchronous UI prop updates into a dedicated helper for better reuse.
Changes:
- Refactors
performOperationsto remove the “triggered by event” boolean and extracts synchronous-props logic intoapplySynchronousUpdates(+partitionUpdates/ feature-flag helper). - Adds Android draw-pass detection (
DrawPassDetector) and a “non-layout operations only” pathway invoked when events arrive during draw. - Adds an Android Draw Pass example screen and tweaks StickyHeaderExample to exercise layout changes during scroll.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react-native-reanimated/apple/reanimated/apple/native/NativeProxy.mm | Updates call site for new performOperations() signature |
| packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NodesManager.java | Adds draw-pass-aware operation execution + new non-layout path |
| packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NativeProxy.java | Updates native method signatures + routes flush via draw-pass-aware path |
| packages/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/DrawPassDetector.java | New helper to track whether UI thread is currently in a draw pass |
| packages/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h | Updates native proxy API (adds non-layout ops) |
| packages/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp | Implements/exports new JNI methods for non-layout ops |
| packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h | Updates public API + adds private applySynchronousUpdates |
| packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp | Extracts synchronous updates; adds non-layout-only entrypoint |
| packages/react-native-reanimated/Common/cpp/reanimated/Fabric/updates/UpdatesRegistry.h | Adds getPendingUpdates() API |
| packages/react-native-reanimated/Common/cpp/reanimated/Fabric/updates/UpdatesRegistry.cpp | Implements getPendingUpdates() |
| apps/fabric-example/ios/Podfile.lock | Updates CocoaPods checksums from cherry-pick |
| apps/common-app/src/apps/reanimated/examples/index.ts | Registers new Android Draw Pass example |
| apps/common-app/src/apps/reanimated/examples/StickyHeaderExample.tsx | Adds animated width to force layout updates during scroll |
| apps/common-app/src/apps/reanimated/examples/AndroidDrawPassExample.tsx | New example demonstrating the historical crash + fix |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
tjzel
approved these changes
Mar 19, 2026
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.
Cherry picks #9078 and #9072