Home > Mobile >  How do I add routes to my react native app navigation, but keep it out of my tab navigation?
How do I add routes to my react native app navigation, but keep it out of my tab navigation?

Time:07-13

I've watched tutorials and looked at the docs however I still don't get it, I need someone to explain using my situation/code.

My navigation setup is similar to Instagram. Bottom tab navigation has Home/Search/Inventory/Profile.

Here is my navigation file:

import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { PresenceTransition, Text, View } from "native-base";
import Home from "../../screens/Home";
import Profile from "../../screens/Profile";
import InventoryIcon from "../svg/InventoryIcon";
import SearchIcon from "../svg/SearchIcon";
import UserIcon from "../svg/UserIcon";
import HomeIcon from "../svg/HomeIcon";
import Search from "../../screens/Search";
import Inventory from "../../screens/Inventory";
import authStore from "../../zustand/authStore";
import Login from "../../screens/Login/Login";
import { SafeAreaView } from "react-native-safe-area-context";
import { TouchableOpacity } from "react-native";
import userDataStore from "../../zustand/userDataStore";
import Avatar from "../Avatar";

const Tab = createBottomTabNavigator();

export default function BottomNavigation() {
  const currentUser = authStore((state) => state.currentUser);

  if (!currentUser)
    return (
      <SafeAreaView>
        <Login />
      </SafeAreaView>
    );

  return (
    <Tab.Navigator
      tabBar={(props) => <TabBar {...props} />}
      initialRouteName="Home"
      screenOptions={({ route }) => ({
        headerShown: false,
        tabBarStyle: {
          elevation: 0,
          borderTopWidth: 0,
          backgroundColor: "#2563eb",
        },
        tabBarShowLabel: false,
      })}
    >
      <Tab.Screen name="Home" component={Home} />
      <Tab.Screen name="Search" component={Search} />
      <Tab.Screen name="Inventory" component={Inventory} />
      <Tab.Screen name="Profile" component={Profile} />
    </Tab.Navigator>
  );
}

function TabBar({ state, descriptors, navigation }) {
  const currentUser = authStore((state) => state.currentUser);
  const userData = userDataStore((state) => state.userData);
  return (
    <View className="bg-blue-600 py-4" style={{ flexDirection: "row" }}>
      {state.routes.map((route, index) => {
        const { options } = descriptors[route.key];

        const isFocused = state.index === index;

        let params;
        if (route.name === "Profile") {
          params = {
            uid: currentUser?.uid,
          };
        }
        const onPress = () => {
          const event = navigation.emit({
            type: "tabPress",
            target: route.key,
          });

          if (route.name === "Profile" && !event.defaultPrevented) {
            navigation.navigate(route.name, params);
            return;
          }

          if (!isFocused && !event.defaultPrevented) {
            navigation.navigate(route.name, params);
          }
        };

        const onLongPress = () => {
          navigation.emit({
            type: "tabLongPress",
            target: route.key,
          });
        };

        return (
          <TouchableOpacity
            accessibilityRole="button"
            accessibilityState={isFocused ? { selected: true } : {}}
            accessibilityLabel={options.tabBarAccessibilityLabel}
            testID={options.tabBarTestID}
            onPress={onPress}
            onLongPress={onLongPress}
            style={{ flex: 1 }}
          >
            <View className="relative flex w-full flex-1 items-center justify-center">
              <TabIcon
                currentUserProfilePicture={userData?.profilePicture}
                name={route.name}
              />
              <PresenceTransition
                visible={isFocused}
                initial={{ opacity: 0, scale: 0 }}
                animate={{
                  opacity: 1,
                  scale: 1,
                  transition: {
                    duration: 200,
                  },
                }}
                className="absolute -bottom-7 h-4 w-4 rounded-sm bg-white"
              />
            </View>
          </TouchableOpacity>
        );
      })}
    </View>
  );
}

function TabIcon({
  name,
  currentUserProfilePicture,
}: {
  name: string;
  currentUserProfilePicture: undefined | null | string;
}) {
  if (name === "Home") {
    return <HomeIcon svgClassName="text-white w-6 h-6" />;
  }
  if (name === "Search") {
    return <SearchIcon svgClassName="text-white w-6 h-6" />;
  }
  if (name === "Collections") {
    return <CollectionsIcon svgClassName="text-white w-6 h-6" />;
  }
  if (name === "Profile") {
    return currentUserProfilePicture ? (
      <Avatar
        url={currentUserProfilePicture}
        alt="Your profile"
        className="h-6 w-6"
      />
    ) : (
      <UserIcon svgClassName="text-white w-6 h-6" />
    );
  }
  return null;
}

Now, the problem is I want to add a Settings screen. This screen shouldn't be in the bottom tab bar, it should only be navigated to from the Profile screen. If I add it to the navigation, it is automatically added.

I could do something like:

const hiddenRoutes = ["Settings"]

if (hiddenRoutes.includes(route.name) {
   return;
}

But this seems quite hacky to me, I feel its wrong.

How should I best declare routes, but keep them out of the bottom tab navigation?

CodePudding user response:

You will want to create another navigation layer for your profile screen

To make the stack navigation for the profile screen:

const ProfileStack = createNativeStackNavigator<ProfileStackParamList>();
function ProfileNavigator() {
  return (
    <ProfileStack.Navigator >
      <ProfileStack.Screen
        name={"Profile"}
        component={Profile}
        options={() => ({
          title: "Profile",
        })}
      />
  <ProfileStack.Screen
    name={"Settings"}
    component={Settings}
    options={() => ({
      title: "Settings",
    })}
  />
</ProfileStack.Navigator>

); }

Then in where you are making your Tab navigator use this stack navigation in the component

  <Tab.Screen name="Profile" component={ProfileNavigator} />
  • Related