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} />