Repository navigation
fix(patches): run the useInsertionEffect cleanup of a component removed inside a hidden Activity - #101577
Conversation
…ed inside a hidden Activity Fabric in react-native 0.86 (React 19.2.3 renderer, native-oss flags) skips the insertion effect cleanup in commitDeletionEffectsOnFiber when the deleted fiber sits in a hidden Offscreen subtree, because enableHiddenSubtreeInsertionEffectCleanup stayed false in that fork. react-dom 19.2 runs it, and React 19.3 removed the flag and runs it unconditionally (react/react#30954, Expensify#34372, Expensify#35918). Patch 044 drops the guard in the dev, prod and profiling builds. react-test-renderer 19.2.3 gets the same patch so jest matches the runtime, and a test pins the three paths: hide only, removal while hidden, removal while visible.
|
|
…the insertion-cleanup patch details
…hidden-subtree-insertion-effect-cleanup
…he insertion-cleanup test
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-09-25.at.11.38.44.movScreen.Recording.2026-09-25.at.11.39.43.movScreen.Recording.2026-09-25.at.11.43.15.movAndroid: mWeb ChromeScreen.Recording.2026-09-25.at.11.47.02.moviOS: HybridAppScreen.Recording.2026-09-25.at.11.46.02.moviOS: mWeb SafariScreen.Recording.2026-09-25.at.11.48.03.movMacOS: Chrome / SafariScreen.Recording.2026-09-25.at.11.44.18.mov |
|
🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here. |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/roryabraham in version: 9.4.94-0 🚀
|
|
🚀 Deployed to production by https://github.com/Julesssss in version: 9.4.94-0 🚀
Bundle Size Analysis (Sentry): |
Explanation of Change
When a component is removed while it is hidden, for example inside a hidden
<Activity>or on a screen frozen by react-freeze, the native renderer skips the cleanup of itsuseInsertionEffect, so whatever that effect registered is never released. This PR backports the React fix that makes the cleanup run. React DOM on web already works this way, and React 19.3 does on every platform.In the app
In the code
patches/react-native/react-native+0.86.0+044+run-insertion-effect-cleanup-in-hidden-subtree.patchremoves theoffscreenSubtreeWasHiddencheck in front of the insertion effect cleanup incommitDeletionEffectsOnFiber, in the development, production and profiling builds of the Fabric renderer. This check is controlled by theenableHiddenSubtreeInsertionEffectCleanupflag, which React turned on for React DOM (facebook/react#34372) and later removed (facebook/react#35918), but which is still off in the React Native 0.86 build.patches/react-test-renderer/react-test-renderer+19.2.3+001+run-insertion-effect-cleanup-in-hidden-subtree.patchmakes the same change inreact-test-renderer, so that Jest tests behave like the app.tests/unit/InsertionEffectCleanupInHiddenActivityTest.tsxchecks that hiding a component does not run the cleanup, and that removing it runs the cleanup both when it is hidden and when it is visible.Impact on the app
usePressabilityand the Animated props hook in React Native, andusePreventRemoveandPreventRemoveProviderin React Navigation. Code insrc/does not useuseInsertionEffect.freezeOnBlur.Fixed Issues
$ #98254
PROPOSAL: N/A
Tests
npm install. Verify that patch-package appliesreact-native@0.86.0 (44 run-insertion-effect-cleanup-in-hidden-subtree)andreact-test-renderer@19.2.3 (1 run-insertion-effect-cleanup-in-hidden-subtree)without warnings.node_modules/react-native/Libraries/Renderer/implementations/ReactFabric-dev.jsand find the call tocommitHookEffectListUnmount(Insertion, ...)incommitDeletionEffectsOnFiber. Verify that it is no longer preceded byoffscreenSubtreeWasHidden ||, while theLayoutcall directly below it still is.navigation object hasn't been initialized,getSnapshot should be cachedandstate or screen passed in the paramsalso appear without this patch, so they are not new.Offline tests
N/A. This change only affects how React removes components, and it does not involve the network or Onyx.
QA Steps
Steps 2 and 3 remove a frozen screen together with the screen that covers it, which is the case this PR changes. Step 1 checks that buttons and animations, which use insertion effects, still work.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
android-1-create-expense.mp4
android-2-inbox-thread.mp4
android-3-delete-workspace.mp4
iOS: Native
ios-1-create-expense.mp4
ios-2-inbox-thread.mp4
ios-3-delete-workspace.mp4
MacOS: Chrome / Safari
web-1.mp4
web-2.mp4
web-3.mp4