Skip to content

iOS: RCTComponentViewRegistry: Attempt to recycle a mounted view when navigating inside tab stack while removing multiple screens #3263

@shariqahmed525

Description

@shariqahmed525

Description

When navigating with CommonActions.reset to remove multiple screens from the stack on iOS, the app crashes with:

RCTComponentViewRegistry: Attempt to recycle a mounted view

Image

This happens in two scenarios:

  1. Login redirect: After login, I reset the stack to redirect the user into the TabNavigator.
  2. Nested navigation reset: Inside a tab stack (HomeTab), when moving forward from ScreenB to ScreenC while removing ScreenA and ScreenB from the stack.

On Android this works as expected. The crash only occurs on iOS.


Navigation hierarchy

RootStack
│
├── Login
├── Otp
└── TabNavigator
    ├── HomeTab
    │   └── HomeStack
    │       ├── HomeScreen
    │       ├── ScreenA
    │       ├── ScreenB   <-- starting point
    │       └── ScreenC   <-- destination
    │
    ├── SalesTab
    │   └── SalesStack
    │       ├── SalesScreen
    │       ├── ScreenX
    │       └── ScreenY
    │
    └── SettingsTab
        └── SettingsStack
            ├── SettingsScreen
            └── ...

Environment

  • React Native: 0.81.0
  • React Navigation: 7.0.14
  • @react-navigation/native-stack: 7.2.0
  • @react-navigation/stack: 7.1.1
  • react-native-screens: ^4.9.1
  • @react-navigation/bottom-tabs: ^7.2.0

Steps to Reproduce

  1. RootStack contains:

    • AuthScreen (no AuthStack wrapper)
    • TabNavigator (no AppStack wrapper)
    • Each tab has its own stack.
  2. After login

    navigation.reset({
      index: 0,
      routes: [{ name, params }],
    });

    → Works fine most of the time.

  3. In HomeTab

    • Start on HomeScreen.
    • Navigate: HomeScreen → ScreenA → ScreenB.
    • From ScreenB, navigate to ScreenC while removing ScreenB and ScreenA.

    Code:

    navigation.dispatch(state => {
      const keepUntil = Math.max(0, state.routes.length - 2);
    
      const remainingRoutes = state.routes.slice(0, keepUntil).map(route => ({
        name: route.name,
        params: route.params,
      }));
    
      const routes = [...remainingRoutes, { name: 'screenC', params: {} }];
    
      return CommonActions.reset({
        ...state,
        routes,
        index: routes.length - 1,
      });
    });
  4. Expected stack: HomeScreen → ScreenC.

  5. Actual behavior: iOS crashes with:

    RCTComponentViewRegistry: Attempt to recycle a mounted view
    

Snack or a link to a repository

https://snack.expo.io/

Screens version

4.9.1

React Native version

0.81.0

Platforms

iOS

JavaScript runtime

Hermes

Workflow

React Native (without Expo)

Architecture

Fabric (New Architecture)

Build type

Debug mode

Device

Real device

Device model

iPhone 14

Acknowledgements

Yes

Metadata

Metadata

Assignees

No one assigned

    Labels

    Missing infoThe user didn't precise the problem enoughMissing reproThis issue need minimum repro scenarioPlatform: iOSThis issue is specific to iOS

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions