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!