You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ReactNativeBrownfield.createView adds an OnBackPressedCallback without a LifecycleOwner and never removes it. ReactNativeFragment.onCreateView calls createView for each new view, so callbacks from destroyed views remain enabled for the lifetime of the activity.
In a single-activity host, back works on the first visit to the React Native screen. After leaving and reopening it, hardware/gesture back stops working.
Environment
@callstack/react-native-brownfield
5.1.0
React Native
0.87.0
Android
API 35 emulator
Host
Single activity; ReactNativeFragment is directly on the activity fragment back stack
The reproduction reduces this repository's Android example to one AppCompatActivity, one native fragment, one ReactNativeFragment, and a React Native component containing only Text. It has no JavaScript navigation stack or BackHandler.
Tap Open React Native.
Press hardware or gesture back. The native fragment returns.
Tap Open React Native again.
Press back again.
Expected: the native fragment returns.
Actual: the React Native fragment remains visible. Further visits add further callbacks, and back remains broken until the activity is recreated.
Screen.Recording.2026-09-07.at.15.02.48.mov
Cause
createView registers the callback using the non-lifecycle-aware overload:
That overload requires explicit removal, but no removal exists. ReactNativeFragment.onCreateView calls createView again for every view creation.
When the active callback disables itself to pass an unhandled press to the dispatcher, a callback retained from the previous view receives it instead. The dispatcher therefore never reaches the host fragment manager.
The lifecycle observer at lines 232–233 does not cover this: ReactNativeFragment supplies a delegate, so that branch is skipped, and the observer does not remove the callback in any case.
Expected behaviour
Callbacks belonging to destroyed fragment views should not receive back presses. Back should behave the same on every visit.
Summary
ReactNativeBrownfield.createViewadds anOnBackPressedCallbackwithout aLifecycleOwnerand never removes it.ReactNativeFragment.onCreateViewcallscreateViewfor each new view, so callbacks from destroyed views remain enabled for the lifetime of the activity.In a single-activity host, back works on the first visit to the React Native screen. After leaving and reopening it, hardware/gesture back stops working.
Environment
@callstack/react-native-brownfieldReactNativeFragmentis directly on the activity fragment back stackMinimal reproduction
findoo/react-native-brownfield-back-press-repro
The reproduction reduces this repository's Android example to one
AppCompatActivity, one native fragment, oneReactNativeFragment, and a React Native component containing onlyText. It has no JavaScript navigation stack orBackHandler.Expected: the native fragment returns.
Actual: the React Native fragment remains visible. Further visits add further callbacks, and back remains broken until the activity is recreated.
Screen.Recording.2026-09-07.at.15.02.48.mov
Cause
createViewregisters the callback using the non-lifecycle-aware overload:That overload requires explicit removal, but no removal exists.
ReactNativeFragment.onCreateViewcallscreateViewagain for every view creation.When the active callback disables itself to pass an unhandled press to the dispatcher, a callback retained from the previous view receives it instead. The dispatcher therefore never reaches the host fragment manager.
The lifecycle observer at lines 232–233 does not cover this:
ReactNativeFragmentsupplies a delegate, so that branch is skipped, and the observer does not remove the callback in any case.Expected behaviour
Callbacks belonging to destroyed fragment views should not receive back presses. Back should behave the same on every visit.
Related
mBackPressedCallbacknot re-enabled after hardware back handler is called #227 fixes a callback not being re-enabled after forwarding a back press. This issue concerns callbacks from destroyed views not being removed.