I setup Bottom tab navigator in my react native app with typescript.
I have Home, Explore, Ticket and Profile screen in bottom tabs.
My Ticket screen is just showing a simple text, when i click on empty area on the screen it automatically redirecting back to home tab, same for other tabs.
**i'm developing on macOS
machin: macbook air
OS: macOS sonoma 14.4.1
memory: 8 GB
chip: apple M2
packages i use
"react-native": "0.74.2"
"react-navigation/bottom-tabs": "^6.5.20"
here is my code.
AppStack.tsx
import React from "react"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import { AppStackParamList } from "@src/types"; import { SearchEvent } from "@src/screens"; import { BottomStack } from "./BottomStack"; import { EventDetails } from "@src/screens/event-detail/EventDetails"; import { useNavigationLogger } from "@src/hooks/useNavigationLogger"; const { Navigator, Screen } = createNativeStackNavigator<AppStackParamList>(); export function AppStack(): React.JSX.Element { useNavigationLogger(); return ( <Navigator screenOptions={{ headerShown: false }} initialRouteName="BottomStack"> <Screen name="BottomStack" component={BottomStack} /> <Screen name="EventDetail" component={EventDetails} /> <Screen name="SearchEvent" component={SearchEvent} /> </Navigator> ); } BottomStack.tsx
import React from "react"; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { AppStackParamList } from "@src/types"; import { Home, Explore, Tickets, Profile } from "@src/screens"; import OcticonsHomeIcon from "react-native-vector-icons/Octicons"; import AntDesignSearchIcon from "react-native-vector-icons/AntDesign"; import MaterialCommunityIconsTicketIcon from "react-native-vector-icons/MaterialCommunityIcons"; import AntDesignProfileIcon from "react-native-vector-icons/AntDesign"; import { ViewStyle } from "react-native"; import { colors } from "@src/utils"; interface IconProps { focused: boolean; color: string; size: number; } const HomeIcon: React.FC<IconProps> = ({ focused, color, size }) => ( <OcticonsHomeIcon name={focused ? "home" : "home"} size={size} color={color} /> ); const SearchIcon: React.FC<IconProps> = ({ focused, color, size }) => ( <AntDesignSearchIcon name={focused ? "search1" : "search1"} size={size} color={color} /> ); const TicketIcon: React.FC<IconProps> = ({ focused, color, size }) => ( <MaterialCommunityIconsTicketIcon name={focused ? "ticket-confirmation" : "ticket-confirmation"} size={size} color={color} /> ); const ProfileIcon: React.FC<IconProps> = ({ focused, color, size }) => ( <AntDesignProfileIcon name={focused ? "user" : "user"} size={size} color={color} /> ); const screenOptions = ({ route }: { route: any }) => ({ tabBarIcon: ({ focused, color, size }: IconProps) => { switch (route.name) { case "Home": return <HomeIcon focused={focused} color={color} size={size} />; case "Explore": return <SearchIcon focused={focused} color={color} size={size} />; case "Tickets": return <TicketIcon focused={focused} color={color} size={size} />; case "Profile": return <ProfileIcon focused={focused} color={color} size={size} />; default: return null; } }, tabBarActiveTintColor: colors.primary, tabBarInactiveTintColor: colors.textSecondary, headerShown: false, tabBarLabelStyle: { fontSize: 12, }, tabBarStyle: { height: 60, backgroundColor: colors.black, justifyContent: "center", borderTopWidth: 0, } as ViewStyle, }); const BottomTab = createBottomTabNavigator<AppStackParamList>(); export function BottomStack(): React.ReactElement { return ( <BottomTab.Navigator initialRouteName="Home" screenOptions={screenOptions}> <BottomTab.Screen name="Home" component={Home} /> <BottomTab.Screen name="Explore" component={Explore} /> <BottomTab.Screen name="Tickets" component={Tickets} /> <BottomTab.Screen name="Profile" component={Profile} /> </BottomTab.Navigator> ); } Tickets.tsx
import React from "react"; import { Text, View } from "react-native"; export function Tickets({}): React.JSX.Element { console.log("Tickets screen rendered"); return ( <View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}> <Text>this is Tickets screen</Text> </View> ); } Profile.tsx
import { Nf3Button } from "@src/components/common"; import React from "react"; import { Text, View } from "react-native"; import { useAppDispatch } from "@src/hooks"; import { logout } from "@src/store/slices/user-slice"; export function Profile({}): React.JSX.Element { const dispatch = useAppDispatch(); return ( <View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}> <Text>this is profile screen</Text> <Nf3Button title="logout" style={{ alignSelf: "center" }} onPress={() => dispatch(logout())} /> </View> ); } i use a custom hook to log the navigation state change. this is the code of hook to logs the navigation state change.
useNavigationLogger.ts
import { useEffect } from "react"; import { useNavigation, useNavigationState } from "@react-navigation/native"; export function useNavigationLogger() { const navigation = useNavigation(); const state = useNavigationState((state) => state); useEffect(() => { const unsubscribe = navigation.addListener("state", () => { console.log("Navigation state changed:", JSON.stringify(state, null, 2)); }); return unsubscribe; }, [navigation, state]); } when i open the app and navigate to Ticket screen it logs
LOG Tickets screen rendered LOG Navigation state changed: undefined then when i click on empty area of the Ticket screen then it logs
LOG Navigation state changed: { "stale": false, "type": "stack", "key": "stack-mb5sp5e4a4kn9dj_0kHvK", "index": 0, "routeNames": [ "BottomStack", "EventDetail", "SearchEvent" ], "routes": [ { "key": "BottomStack-VQT1LwwFSP7qtfSF10J6h", "name": "BottomStack", "state": { "stale": false, "type": "tab", "key": "tab-euFwrJf651_yFCB2jAHQJ", "index": 2, "routeNames": [ "Home", "Explore", "Tickets", "Profile" ], "history": [ { "type": "route", "key": "Home-qKX3M5AQ2M5H9ATqwSzi6" }, { "type": "route", "key": "Tickets-X9PZhIsfM7R4O4HJtEfI_" } ], "routes": [ { "name": "Home", "key": "Home-qKX3M5AQ2M5H9ATqwSzi6" }, { "name": "Explore", "key": "Explore-oxyMhsKyagZFlG5oXrFPM" }, { "name": "Tickets", "key": "Tickets-X9PZhIsfM7R4O4HJtEfI_" }, { "name": "Profile", "key": "Profile-5BhwfhOYgLMcFIFt-5Adq" } ] } } ] }```