Home > Net >  Navigation between screens with nested Navigation
Navigation between screens with nested Navigation

Time:05-20

Having a bit of trouble getting to navigate between screens in the nested navigation (Tabs and screens). Here is my code:

This is the Tab Stack navigator

const AppStack = () => {
  return (
    <Tab.Navigator
    initialRouteName="Scan"
    screenOptions={{
      headerShown: false,
      tabBarActiveTintColor: 'red',
      tabBarInactiveTintColor: 'black',
    }}>
      <Tab.Screen name="Market" component={MarketplaceScreen} options={{
          tabBarLabel: 'Marketplace',
          tabBarIcon: ({ focused, color, size }) => (
            <Icon
                name="shopping"
                size={24}
                color={focused ? color : 'black'}
 
              />
          ),
        }} />
      <Tab.Screen name="Discover" component={DiscoverScreen} options={{
          tabBarLabel: 'Discover',
          tabBarIcon: ({ focused, color, size }) => (
            <Icon
                name="map-search"
                size={24}
                color={focused ? color : 'black'}
 
              />
          ),
        }} />
      
        <Tab.Screen name="Wallet" component={WalletScreen} options={{
          tabBarLabel: 'Wallet',
          tabBarIcon: ({ focused, color, size }) => (
            <Icon
                name="wallet"
                size={24}
                color={focused ? color : 'black'}
 
              />
          ),
        }} />
        <Tab.Screen name="Account" component={AccountScreen} options={{
          tabBarLabel: 'Account',
          tabBarIcon: ({ focused, color, size }) => (
            <Icon
                name="account"
                size={24}
                color={focused ? color : 'black'}
 
              />
          ),
        }} />
        
    </Tab.Navigator>
  );

This is the Screen Stack:

  function App() {
    return (
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen
            name="Profile"
            component={ProfileScreen}/>
        </Stack.Navigator>
      </NavigationContainer>
    );
  }

This is how I set up the Account Screen:

  function AccountScreen(navigation:any) {
      return (
        <View style={styles.container}>
              <TouchableOpacity onPress={() =>navigation.navigate('Profile') }><Text>PRESS HERE </Text></TouchableOpacity>
    </View>

The error I keep getting is "navigation.navigate is not a function"

Any help is welcome, I'm just out of ideas at the moment, Thank you

CodePudding user response:

It depends on the following question: Do you want the ProfileStack to be a tab as well? If the answer is positive, then you need to nest the ProfileStack inside a tab. If the answer is negative, then you need to nest the AppStack inside the stack of the profile defined inside App.

Assuming that ProfileStack should not be a tab, then the solution is as follows.

function App() {
    return (
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen
            name="Profile"
            component={ProfileScreen}
          />
          <Stack.Screen
            name="Tabs"
            component={AppStack}
          />
        </Stack.Navigator>
      </NavigationContainer>
    );
  }

Notice, that ProfileScreen won't have a tab bar and that the initial screen is Profile. The only way for the user to navigate to a screen that contains a tab bar is some sort of button in ProfileScreen. This is usually not what you want.

If you want the ProfileStack to be a tab, then you need to do it the other way around.

const ProfileStack = () {
    return (
        <Stack.Navigator>
          <Stack.Screen
            name="Profile"
            component={ProfileScreen}
           />
        </Stack.Navigator>
    )
}

const AppStack = () => {
  return (
    <Tab.Navigator
    initialRouteName="Scan"
    screenOptions={{
      headerShown: false,
      tabBarActiveTintColor: 'red',
      tabBarInactiveTintColor: 'black',
    }}>
      <Tab.Screen name="ProfileStack" component={ProfileStack} options={{
          tabBarLabel: 'Profile',
          tabBarIcon: ({ focused, color, size }) => (
            <Icon
                name="profile" // or whatever
                size={24}
                color={focused ? color : 'black'}
 
              />
          ),
        }} />

...

And in your App you need to use the AppStack instead.

function App() {
    return (
      <NavigationContainer>
        <AppStack />
      </NavigationContainer>
    );
  }

Furthermore, you need to destructure the navigation object from the screen props using curly braces.

If ProfileStack is now actually a tab, you need to navigate as follows.

function AccountScreen({navigation}) {
      return (
        <View style={styles.container}>
              <TouchableOpacity onPress={() => navigation.navigate('ProfileStack') }><Text>PRESS HERE </Text></TouchableOpacity>
    </View>)

CodePudding user response:

I managed to solve this by making a blank expo project with tabs in typescript to see if I could spot the difference. This is how I got it to work:

I set up the tabs and app stacks by copying the expo project in the app.tsx.

I then had to create a types.tsx file which detailed all of the routes. This file is also generated by expo so its a straight copy and paste (With your naming conventions of course)

I had to change the account screen to:

function AccountScreen({ navigation }: { navigation: any }) { ... }

Then the navigation worked like:

      <TouchableOpacity onPress={() =>navigation.navigate('Profile') }><Text>PRESS HERE </Text></TouchableOpacity>

I then had to add this to the profile screen:

export default function ProfileScreen({ navigation }: RootStackScreenProps<'Profile'>) { ... }

This is a silly problem, so I hope my answer can help someone!

  • Related