react-navigation / react-navigation/react-navigation

React Native nested navigation unexpected behaviour

Open
#12,086 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug platform:android platform:ios repro provided
Dominant language
TypeScript
Stars
24.5k
Forks
5.1k
Avg merge
1d 5h
Merged PRs (30d)
18

Description

Current behavior

I am using 'react-navigation/native' in an Expo managed project and I have built using 'react-navigation/native-stack' and 'react-navigation/bottom-tabs' a navigation structure as follows:

 <Stack.Navigator screenOptions={commonHeaderStyle}>
      {username && IdUser ? //If the user is not logged in its data isn't present
        <Stack.Screen
          name="DefaultLogged"
          component={TabNavigator}
          initialParams={{IdUser, username}}
          options={{headerShown: false}}
        />  
        : 
        <Stack.Screen
          name="DefaultHome"
          component={DefaultScreen}
          options={(props) => ({
            headerShown: true,
            header: () => (<HomeHeader navigation={props.navigation} />),
          })}
        />
      }
      <Stack.Screen
        name="Default"
        component={DefaultScreen}
        options={(props) => ({
          headerShown: true,
          header: () => (<HomeHeader navigation={props.navigation} />),
        })}
      />
      <Stack.Screen
        name="Logged"
        component={TabNavigator}
        initialParams={{IdUser:null, username:null}}
        options={{headerShown: false}}
      />
    </Stack.Navigator>

Where the TabNavigator is the following:

<Tab.Navigator>
      <Tab.Screen
        name="ProfileRoot"
        component={ProfileRoot}
        initialParams={{IdUser, username}}
        options={{title: 'Perfil', headerShown: false}}
      />
      <Tab.Screen
        name="WorkersRoot"
        component={WorkersRoot}
        options={{ title: 'Trabajadores', headerShown: false}}
      />
</Tab.Navigator>

And my ProfileRoot and WorkersRoot components are respectively:

<Stack.Navigator screenOptions={commonHeaderStyle}>
      <Stack.Screen
        name="Profile"
        component={ProfileScreen}
        options={{title: 'Perfil'}}
      />
      <Stack.Screen
        name="UserReviews"
        component={UserReviewsScreen}
        initialParams={{ category: null, IdUser, username}}
        options={({ route }) => ({ title: `Reseñas de ${route.params.category}` })}
      />      <Stack.Screen
        name="WorkersForm"
        initialParams={{IdUser, username}}
        component={WorkerFormScreen}
        options={{title: 'Subir oficio'}}
      />
      <Stack.Screen
        name="User"
        component={UserScreen}
        initialParams={{ IdUser: null, username: null }}
        options={({ route }) => ({ title: `Perfil de ${route.params.username}`})}
      />
</Stack.Navigator>
 <Stack.Navigator screenOptions={commonHeaderStyle}>
      <Stack.Screen
        name="WorkersCategories"
        component={CategoriesScreen}
        initialParams={{ type: 'trabajador' }}
        options={{title: 'Encontrar trabajador' }}
      />
      <Stack.Screen
        name="Workers"
        component={WorkersScreen}
        initialParams={{ category: null }}
      />
</Stack.Navigator>

My main issue is that when I navigate to WorkersRoot and to the Workers screen, I have an action that sends me to the ProfileRoot and to the user screen with some params. Example function:
navigation.navigate('ProfileRoot', { screen: 'User', params: { IdUser: worker.id_user, username: worker.username }})

And when I hit the return button or press the Tab icon to send me to the first screen in the ProfileRoot stack I get correctly sent to that screen, but when I press the icon of the WorkersRoot Tab and press again the ProfileRoot Tab (to return to the Profile screen as expected, the User screen gets rendered instead. So once I have navigated to the User's screen from the WorkersRoot Tab, it seems there is no way to discard this screen from the ProfileRoot stack.

Here is a link to a video showing the bug

What I've tried:
-To reset navigation using dispatch every time one gets redirected to the ProfileRoot from the WorkersRoot

I could not reproduce the bug on Snack. I am currently reproducing it on a repo.

Expected behavior

Expected behaviour: navigate correctly between Tabs and the stack should be resetted

Reproduction

Exact same issue

Platform
  • Android
  • iOS
  • Web
  • Windows
  • MacOS
Packages
  • @react-navigation/bottom-tabs
  • @react-navigation/drawer
  • @react-navigation/material-top-tabs
  • @react-navigation/stack
  • @react-navigation/native-stack
  • react-native-tab-view
Environment
  • [] I've removed the packages that I don't use
package version
@react-navigation/native "^6.1.18"
@react-navigation/bottom-tabs "^6.6.1"
@react-navigation/native-stack "^6.9.26"
react-native-safe-area-context "4.10.5"
react-native-screens "^3.31.1"
react-native "0.74.3"
expo "~51.0.22"
node "20.11.1"
npm or yarn "10.2.4"

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked rn-minimum reproduction and the navigation.navigate('ProfileRoot', ...) call; inspect the nested tab and native-stack state transitions when switching tabs. Confirm the expected reset behavior on Android and iOS, then isolate a minimal reproducible case or failing test showing whether the User screen remains in the ProfileRoot stack.

Written by the indexing model from the issue text.

Assessment

Tech stack
react-native, typescript
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.