software-mansion / software-mansion/react-native-screens
[Android] navigate reordering a buried Screen (hosting a nested navigator) leaks a Screen that swallows all touches — #2466 regression on 4.26.2
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 3.7k
- Forks
- 714
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 71
Description
Description
On Android + New Architecture (Fabric), when @react-navigation navigate()
repeatedly reorders already-buried routes (RN7 navigate behavior — when a
getId match is found deeper in the stack, the route is reordered to the top
instead of a new one being pushed) and you then pop back down to a screen sitting
underneath the churn, react-native-screens leaves a leaked Screen overlaying
the tree that swallows every touch. The underlying screen is fully rendered and
visible, but Pressable/Touchable — and even a nested tab bar — stop responding.
Pan/scroll gestures still work (RNGH uses a separate touch path — the tell).
This reproduces #2150 / #2219, which were closed as fixed by #2466 (4.6.0)
but regress on 4.26.2 (current latest stable).
The topology matters — a flat stack of plain cards does not reproduce it.
The freeze needs a stack screen that hosts a nested navigator sitting
underneath the reorder churn:
Root Stack
├─ ProfileTab ← initial/bottom screen; hosts a nested Bottom-Tab navigator
│ ├─ Collection tab ← the surface that freezes
│ └─ About tab
├─ CollectionList (card, getId = collectionList-<id>) ┐ the two screens
└─ ProfileList (card, getId = profileList-<id>) ┘ you bounce between
Both outer navigator types reproduce it (toggle in the repro):
- JS stack (
@react-navigation/stack): underlying screen stays visible, all
taps dead → the leaked Screen is transparent. - native-stack: underlying screen is fully covered by an opaque blank Screen.
View-hierarchy evidence: in the frozen state, adb shell uiautomator dump
shows ~6 stacked full-screen Screen FrameLayouts under the
NavigationContainer (all but one empty — leaked Screen containers from the
repeated reorders). The real content's buttons are still present and
clickable=true, yet receive no touches.
Workaround: dropping getId on Android for the churned screens (so navigate
pushes fresh instead of reordering) sidesteps it. detachInactiveScreens={false}
masks the freeze but has its own bug (#2978) breaking reanimated/gesture-handler.
Steps to reproduce
npm install
npx expo run:android # New Architecture on by default
- Start on
ProfileTab→ itsCollectiontab. Tap the green TAP ME counter a
couple of times — it increments (touch is alive). - Tap RUN LOOP — it runs
navigate("CollectionList",{id:1})⇄
navigate("ProfileList",{id:1})6× (first two push fresh, the rest reorder
the buried duplicates), thenpopToTop()back toProfileTab. - Back on
ProfileTab(content fully visible), tap TAP ME again, or tap the
nested About tab.
Expected: counter increments; nested tab switches.
Actual: every tap is dead — counter frozen, nested tab bar unresponsive. Swipe
still works.
All the repro logic is a single App.tsx.
Snack or a link to a repository
https://github.com/LeCiel/rn-screens-navigate-reorder-touch-freeze
Screens version
4.26.2
React Native version
0.86.0
Platforms
Android
JavaScript runtime
Hermes
Workflow
Expo bare workflow (expo run:android)
Build type
Debug app & Metro bundler
Device
Android emulator
Device model
Pixel, API 36 (also seen on physical devices)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with App.tsx in the linked reproduction and run npm install followed by npx expo run:android on the New Architecture. Reproduce the navigate loop and pop back to ProfileTab, then use the described Android view-hierarchy evidence to investigate the leaked Screen containers. Done means taps and nested tab switching work after the loop while swipe gestures still work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, react-native, typescript
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100