Search code examples
typescriptreact-nativereact-navigationreact-navigation-bottom-tab

React navigation bottom tabs navigator automatically navigating back to initial screen on touch anywheren on screen


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"
          }
        ]
      }
    }
  ]
}```

Solution

  • so i don't know what was breaking but, i just uninstall the app, deleted node_modules, podfile, package-lock.json, cleaned the npm cache, installed pods rebuild the project from xcode it fix the wired issue.