React Native Navigation v5 triggering a drawer from bottom tabs - javascript

Currently I am trying to tigger the drawer from the bottom nav as you can see here:
My current tabs is the following:
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused }) => {
let iconName;
switch (route.name) {
case 'Home':
iconName = 'window-maximize';
break;
case 'Purchases':
iconName = 'tags';
break;
case 'Notifications':
iconName = 'bell';
break;
case 'Checkout':
iconName = 'shopping-cart';
break;
case 'Orders':
iconName = 'dollar';
break;
case 'Menu':
iconName = 'navicon';
break;
}
return (
<Icon
name={iconName}
size={20}
color={focused ? 'blue' : 'grey'}
/>
);
},
})}
tabBarOptions={{
showLabel: false,
}}>
<Tab.Screen name="Home" component={LandingScreens} />
<Tab.Screen name="Purchases" component={PurchasesScreens} />
<Tab.Screen name="Notifications" component={Notifications} />
<Tab.Screen name="Checkout" component={CheckoutScreens} />
<Tab.Screen name="Orders" component={OrdersScreens} />
<Tab.Screen
name="Menu"
component={Drawer}
listeners={({ navigation }) => ({
tabPress: (e) => {
e.preventDefault();
},
})}
/>
</Tab.Navigator>
</NavigationContainer>
And my Drawer Component is just going to be a custom Drawer component:
const Drawer = ({ navigation }) => {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Home" component={LandingScreens} />
</Drawer.Navigator>
);
};
My question is something like this possible? I was trying to tigger the navigation.openDrawer() from the tabPress but couldn't find the method. I am doing this right, or would I need some sort of custom bottomNav? Any help is much appreciated!
Thanks.

You can either use DrawerActions.openDrawer:
import { DrawerActions } from '#react-navigation/native'
<Tab.Screen
name="Menu"
component={Drawer}
listeners={({ navigation }) => ({
tabPress: (e) => {
e.preventDefault();
navigation.dispatch(DrawerActions.openDrawer())
},
})}
/>
A better solution is to nest the tabs inside the drawer so navigation.openDrawer() works.
https://reactnavigation.org/docs/nesting-navigators#navigator-specific-methods-are-available-in-the-navigators-nested-inside

Related

React Native: bottom tab press not working

in my react-native app I have a bottom tabs navigation, I added a tabPress listener to one of the screens but for some reason now all screens don't work, I can't navigate to a different screen when I tap the icons...
The objective was to lock a screen depending of the day but now ALL screens are locked for some reason and I can't navigate to ANY screen!
<Tab.Navigator /* options here... */>
<Tab.Screen name="Descubre" component={STACK1} />
<Tab.Screen name="Favoritos" component={STACK2}
listeners={{
tabPress: (e) => {
if(root.mapStore.isoWeekDay == 6)
{
e.preventDefault();
}
},
}}
/>
<Tab.Screen name="Pedidos" component={STACK3} />
<Tab.Screen name="Más" component={STACK4}/>
</Tab.Navigator>
I'm guessing this is the default behaviour stablished by React Native for this event, check section Listening to events​
If you want only to block one of the screens in this point, you could do the following:
<Tab.Navigator>
<Tab.Screen name="Screen 1" />
<Tab.Screen name="Screen 2"
options={{
tabBarButton: disabled ? DisabledTabBarButton : EnabledTabBarButton,
}}
/>
</Tab.Navigator>
Where DisabledTabBarButton is:
const DisabledTabBarButton = ({ style, ...props }: BottomTabBarButtonProps) => (
<Pressable disabled style={[{ opacity: 0.2 }, style]} {...props} />
)
And enabled one:
const EnabledTabBarButton = ({ style, ...props }: BottomTabBarButtonProps) => (
<Pressable style={[{ opacity: 1 }, style]} {...props} />
)
Also, you could do the following while creating your tab navigator:
const TabNavigator = createBottomTabNavigator({
First:{
screen: First,
},
Second:{
screen: Second,
},
Third:{
screen: Third,
}
}, defaultNavigationOptions: ({ navigation }) => ({
tabBarOnPress: ({ navigation, defaultHandler }) => {
if (
navigation.state.routeName === "Route disabled"
) {
return null;
}
defaultHandler();
},})

Need help using goBack() in react native

I am having trouble with the back button in the stack navigator. I am getting an error saying undefined is not an object (evaluating '_this.props'). if it works it goes back to a different tab in the bottom stack navigator. Like if I click on book a session and then I go to home and click back it will take me to book a session no matter what. Please help.
This is what I have so far:
function HomeScreen({ navigation }) {
return (
<WebView
source={{
uri: 'https://www.stoodnt.com/'
}}
style={{ marginTop: -120 }}
/>
);
}
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home"
component={HomeScreen}
options={{
headerLeft: () => (
<HeaderBackButton
onPress={() => this.props.navigation.goBack(null)}
/>
),
}}
/>
</HomeStack.Navigator>
);
}
Bottom Navigator:
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'ios-home'
: 'ios-home';
} else if (route.name === 'Book Session') {
iconName = focused ? 'ios-calendar' : 'ios-calendar';
}
else if (route.name === 'Blogs') {
iconName = focused ? 'ios-bookmark' : 'ios-bookmark';
}
else if (route.name === 'Online Courses') {
iconName = focused ? 'ios-book' : 'ios-book';
}
else if (route.name === 'Classes') {
iconName = focused ? 'ios-desktop' : 'ios-desktop';
}
return <Ionicons name={iconName} size={40} color={'orange'} />;
},
})}
tabBarOptions={{
activeTintColor: '#000000',
inactiveTintColor: '#616161',
labelStyle: {
fontSize: 10,
},
style: {
backgroundColor: '#F7F7F7',
},
}}
>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Book Session" component={BookStackScreen} />
<Tab.Screen name="Blogs" component={BlogStackScreen} />
<Tab.Screen name="Online Courses" component={OnlineStackScreen} />
<Tab.Screen name="Classes" component={ClassesStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
try the below code :
function HomeScreen(props) {
return (
<WebView
source={{
uri: 'https://www.stoodnt.com/'
}}
style={{ marginTop: -120 }}
/>
);
}
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home"
component={HomeScreen}
options={({ route, navigation }) => ({
headerLeft: () => (
<HeaderBackButton
onPress={() => navigation.goBack(null)}
/>
),
})}
/>
</HomeStack.Navigator>
);
}```
In functional components, you do not have access to "this". You should either pass navigation from the screen options or use useNavigation.
<HomeStack.Screen
...
options={({navigation}) => (
headerLeft: () => (
// you can use navigation.goBack() here
)
)}
or
// this should be added right under function HomeStackScreen,
// right above the return and you will be able to use it in the screens
const navigation = useNavigation()

React Native tab navigator nested in stack navigator

I'm relatively new to React Native and am struggling with screens. I've gone through the nested navigation documentation (https://reactnavigation.org/docs/nesting-navigators/) which helped me setup the initial nav setup i have, but im having some issues.
I'm attempting to setup the app so it has the initial screen as a "Select User" which has no tab navigation. After selecting the user, you are redirected to a another screen which has tab navigation. I currently have it working however I am unable to access any route/props/params after the initial screen.
I've had to manually import navigation with import { useNavigation } from "#react-navigation/native"; and even though I'm providing params in the Navigation.push, trying to access {route} in my screens states that route is undefined.
My setup of the screens looks similar to below:
const Tab = createBottomTabNavigator();
const WelcomeStack = createStackNavigator();
const HomeStack = createStackNavigator();
const SettingsStack = createStackNavigator();
const Stack = createStackNavigator();
const WelcomeStackScreen = () => (
<WelcomeStack.Navigator>
<WelcomeStack.Screen
name="Welcome"
component={WelcomeScreen}
options={{ headerShown: false }}
/>
<WelcomeStack.Screen
name="SignUp"
component={SignUpScreen}
options={{ headerShown: false }}
/>
</WelcomeStack.Navigator>
);
const HomeStackScreen = () => {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen
name="Search"
component={SearchResultScreen}
options={({ navigation }) => ({
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen
name="Select"
component={SelectScreen}
options={({ navigation, route }) => ({
title: route.params.name,
headerLeft: () => (
<Ionicons
name={"arrow-back"}
size={30}
color={colours.text}
style={{ paddingLeft: 15 }}
onPress={() => {
navigation.goBack();
}}
/>
),
})}
/>
<HomeStack.Screen name="Read" component={ReaderScreen} />
</HomeStack.Navigator>
);
};
function SettingsScreen() {
return (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<Text>TBD</Text>
</View>
);
}
const SettingsStackScreen = () => (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
</SettingsStack.Navigator>
);
const TabNavigator = ({ route }) => (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
switch (route.name) {
case "Home":
iconName = focused ? "home" : "home-outline";
break;
case "Settings":
iconName = focused ? "list" : "list-outline";
break;
default:
break;
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: "tomato",
inactiveTintColor: "gray",
}}
>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsScreen}/>
</Tab.Navigator>
);
export default function App() {
return (
<NavigationContainer theme={navThemeOverride}>
<Stack.Navigator>
<Stack.Screen name="Welcome" component={WelcomeStackScreen} />
<Stack.Screen
name="TabNavigator"
component={TabNavigator}
options={{ headerShown: false }}
navigationOptions={{ gesturesEnabled: false }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Below is a snippet from the Welcome screen navigation
navigation.push("TabNavigator", {
screen: "Home",
params: {
userId: userId,
},
});
Your Home screen you're trying to navigate to from your parent-tab-navigator ... is also a StackNavigator ... and you wanna navigate to Select screen I guess ... so there's an extra level needed for your navigation to work...
navigation.navigate('TabNavigator', {
screen: 'Home', // <--- StackNavigator
params: {
screen: 'Select', // <-- nested inside HomeStack
params: {
title: 'Your custom title for Select screen here ...',
},
},
});
Plus +
There's a double definition for route in your Tab navigator
const TabNavigator = ({ route }) => ( //<--- here
<Tab.Navigator
screenOptions={({ route }) => ({ // <- and here
Instead
function TabNavigator() {
return <Tab.Navigator screenOptions={({ route }) => ({})>{/* ...Tabs... */}</Tab.Navigator>;
}

React navigation issue trying to hide bottom tab navigation

Im trying to make the bottom tab hidden when I navigate to messages room screen, I have tried to use modal but couldnt get it to work .... below is my code, it will be much appreciated if I get some help
Here is my root navigation
return (
<NavigationContainer
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
>
<RootNavigator />
</NavigationContainer>
);
}
const Stack = createStackNavigator();
function RootNavigator() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name='Root' component={BottomTabNavigator} />
</Stack.Navigator>
);
}
and below here is also the bottom tab navigation
export default function BottomTabNavigator() {
const colorScheme = useColorScheme();
return (
<BottomTab.Navigator
initialRouteName='Listing'
tabBarOptions={{
activeTintColor: Colors[colorScheme].tint,
showLabel: false,
}}
>
<BottomTab.Screen
name='Messages'
component={TabtwoNavigator}
options={{
tabBarIcon: ({ color }) => (
<Ionicons name='ios-chatboxes' color={color} size={30} />
),
}}
/>
<BottomTab.Screen
name='MyListing'
component={TabFourNavigator}
options={{
tabBarIcon: ({ color }) => (
<Ionicons name='ios-albums' color={color} size={30} />
),
}}
/>
</BottomTab.Navigator>
);
}
example of one of the tab navigators are below
function TabtwoNavigator() {
return (
<TabTwoStack.Navigator>
<TabTwoStack.Screen name='Messages' component={MessagesScreen} />
<TabTwoStack.Screen name='MessagesRoom' component={MessagesRoomScreen}/>
</TabTwoStack.Navigator>
);
}
Tab will always show if you place the MessagesRoomScreenin BottomTab Navigator. The workaround can be like
function RootNavigator() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
.....
<!-- Add `MessagesRoom` screen here in parent navigator and remove from `TabtwoNavigator` -->
<Stack.Screen name='MessagesRoom' component={MessagesRoomScreen}/>
</Stack.Navigator>
);
}

Header title not changing with bottom navigation React Native Navigation v5

so I 've got nested navigation, as the code shows. Now I am trying to make the header bar. however, when I change the screens from bottom navigation the header remains the same, no matter on what screen I am(always shoes that I am on Browser screen). Also is the React navigation header the best to create a header bar or is better to create a fully custom one. Thank you
I am expecting that the header title will change in accordance with the page.
const Stack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const AuthStack = createStackNavigator();
const TabsScreen = () => (
<Tabs.Navigator shifting={true} initialRouteName="Home" activeColor="#fff">
<Tabs.Screen
name="Home"
component={Browser}
options={{
tabBarLabel: 'Home',
tabBarColor: '#009387',
tabBarIcon: ({color}) => (
),
}}
/>
<Tabs.Screen
name="Sleep"
component={Sleep}
options={{
tabBarLabel: 'Sleep',
tabBarColor: '#694fad',
tabBarIcon: ({color}) => (
),
}}
/>
<Tabs.Screen
name="Settings"
component={SettingWithContext}
options={{
tabBarLabel: 'Settings',
tabBarColor: '#694fad',
tabBarIcon: ({color}) => (
),
}}
/>
</Tabs.Navigator>
);
export default CreateStack = () => {
const [isLoading, setIsLoading] = React.useState(true);
const [userToken, setUserToken] = React.useState(null);
const authContext = React.useMemo(() => {
return {
signIn: () => {
setIsLoading(false);
setUserToken('asdf');
},
signUp: () => {
setIsLoading(false);
setUserToken('asdf');
},
signOut: () => {
setIsLoading(false);
setUserToken(null);
},
};
}, []);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
if (isLoading) {
return ;
}
return (
<AuthContext.Provider value={authContext}>
{userToken ? (
<Stack.Navigator initialRouteName={Browser}>
<Stack.Screen name="Browser" component={TabsScreen} />
<Stack.Screen name="PreScreen" component={PreScreen} />
<Stack.Screen name="Player" component={Player} />
</Stack.Navigator>
) : (
<AuthStack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={RegisterLogin}>
<AuthStack.Screen name="RegisterLogin" component={RegisterLogin} />
<AuthStack.Screen name="Login" component={LoginWithContext} />
<AuthStack.Screen name="Register" component={RegisterWithContext} />
</AuthStack.Navigator>
)}
</AuthContext.Provider>
);
};
If you want to have every tab name to be the top try this: https://reactnavigation.org/docs/screen-options-resolution/
Check out the getHeaderTitle function and the switch statement below that - it helped me achieve this behavoir.
Because you are using nested navigation, and the stack navigator is the parent one, the top header will remain the same for any navigator inside the TabNavigator.
You might want to create instead a stack navigator inside each tab, so each tab will have its own header title and navigation path.
In another hand, you could try using screen options in order to create some business logic to determine which title you want based on the navigation state.
For example:
const Stack = createStackNavigator();
const Tabs = createMaterialBottomTabNavigator();
const AuthStack = createStackNavigator();
const TabsScreen = () => (
<>
<Tabs.Navigator shifting={true} initialRouteName="Home" activeColor="#fff">
<Tabs.Screen
name="Home"
component={Browser}
options={{
tabBarLabel: "Home",
tabBarColor: "#009387",
tabBarIcon: ({ color }) => color,
}}
/>
<Tabs.Screen
name="Sleep"
component={Sleep}
options={{
tabBarLabel: "Sleep",
tabBarColor: "#694fad",
tabBarIcon: ({ color }) => color,
}}
/>
<Tabs.Screen
name="Settings"
component={SettingWithContext}
options={{
tabBarLabel: "Settings",
tabBarColor: "#694fad",
tabBarIcon: ({ color }) => color,
}}
/>
</Tabs.Navigator>
</>
);
let CreateStack = () => {
const [isLoading, setIsLoading] = React.useState(true);
const [userToken, setUserToken] = React.useState(null);
const authContext = React.useMemo(() => {
return {
signIn: () => {
setIsLoading(false);
setUserToken("asdf");
},
signUp: () => {
setIsLoading(false);
setUserToken("asdf");
},
signOut: () => {
setIsLoading(false);
setUserToken(null);
},
};
}, []);
React.useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 1000);
}, []);
if (isLoading) {
return;
}
return (
<AuthContext.Provider value={authContext}>
{userToken ? (
<Stack.Navigator initialRouteName={Browser}>
{/* Added the options prop to the Browser screen*/}
<Stack.Screen
name="Browser"
component={TabsScreen}
options={({ route }) => ({
headerTitle: getHeaderTitle(route),
})}
/>
<Stack.Screen name="PreScreen" component={PreScreen} />
<Stack.Screen name="Player" component={Player} />
</Stack.Navigator>
) : (
<AuthStack.Navigator
screenOptions={{ headerShown: false }}
initialRouteName={RegisterLogin}
>
<AuthStack.Screen name="RegisterLogin" component={RegisterLogin} />
<AuthStack.Screen name="Login" component={LoginWithContext} />
<AuthStack.Screen name="Register" component={RegisterWithContext} />
</AuthStack.Navigator>
)}
</AuthContext.Provider>
);
};
/**
* Method to get the route name based on the component.
*/
const getHeaderTitle = (route) => {
if (route === "Browser") {
return "Home";
} else if (route === "Sleep") {
return "Sleep"
} else if (route === "Settings") {
return "Settings";
} else {
return route;
}
}
export default CreateStack;
The header is a thing in the stack navigation, not however in the tab-navigation.
Your App is using the header of the stack-navigator in which the tab-navigator is nested.
You could nest stack navigators inside your Tab-Navigator to have the header change as you need it to.

Categories

Resources