Tab.Navigator props is not shown - react-native

I am new to react-native.
I want to access the tab Bar Options property of the Tab Navigator tag but it is shown.
Does any know the how to solve this?
here is my code:
import React from 'react';
import {View, StyleSheet, SafeAreaView, Text} from 'react-native';
import {Na vigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import HomeScreen from './app/screens/HomeScreen';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator {/* HERE I Want to use the PROPS!!!!!!! */} >
<Tab.Screen />
</Tab.Navigator>
</NavigationContainer>
);
}
function HomeStack() {
return (
<Stack.Navigator
initialRouteName="HomeScreen"
screenOptions={{
headerStyle: {backgroundColor: '#841548'},
headerTintColor: 'white',
headerTitleStyle: {fontWeight: 'bold'},
}}>
<Stack.Screen
name="HomeScreen"
component={HomeScreen}
options={{title: 'Home Page'}}
/>
</Stack.Navigator>
);
}
const styles = StyleSheet.create({
container: {flex: 1, backgroundColor: 'white'},
});

In case you wanna implement a custom TabBar, you can access props like below:
<Tab.Navigator tabBar={props => <CustomTabBar {...props} />}>
{...}
</Tab.Navigator>

Related

Screen title not centered

This is my HomeScreen.js:
import * as React from 'react';
import HomeScreenStyle from '../styles/ScreenStyles';
import { View, TouchableOpacity, Text, Image, StyleSheet } from 'react-native';
const HomeScreen = ({ navigation }) => {
return (
<View style={HomeScreenStyle.container}>
<Image source = {require("../assets/AppLogo.jpg")}/>
</View>
);
};
export default HomeScreen;
This is my HomeScreenStyle.js
import { StyleSheet } from 'react-native';
const HomeScreenStyle = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default HomeScreenStyle;
And this is my navigator which configures the title:
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import HomeScreen from '../screens/HomeScreen'
const Stack = createNativeStackNavigator();
const MyStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Home' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default MyStack;
As you can see in the photo the screen title is not centered, how can I achieve that?
thank you
Add the following headerTitleAlign: 'center' in the options so the stack screen will be
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Home',headerTitleAlign: 'center' }}
/>
just add headerTitleAlign:'center' to screen options :
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Home',headerTitleAlign:'center' }}
/>

react native navigation.navigate is not working in nested navigator

//Here is my App.js file
import React, {Suspense} from 'react';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
} from 'react-native';
import {
NavigationContainer,
getFocusedRouteNameFromRoute,
} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import DrawerNavigator from './navigation/DrawerNavigator';
const SinginScreens = React.lazy(() => import('./screens/Login/SinginScreens'));
const Billing = React.lazy(() => import('./screens/Home/Billing'));
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Loading = () => {
return <SafeAreaView>{/* <Text>Loading</Text> */}</SafeAreaView>;
};
const Routes = ({navigation}) => {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName={'Main'}>
<Stack.Screen
name={'Main'}
component={DrawerNavigator}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="Billing"
component={Billing}
options={{
headerLeft: null,
headerShown: false,
}}
/>
<Stack.Screen
name="SinginScreen"
component={SinginScreens}
options={{
headerShown: false,
gestureEnabled: false,
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
class App extends React.PureComponent {
render() {
return (
<Suspense fallback={<Loading />}>
<Routes />
</Suspense>
);
}
}
export default App;
//Here is my stack navigator
import React from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import {Button} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
const Dashboard = React.lazy(() => import('../screens/Home/Dashboard.js'));
const Splash = React.lazy(() => import('../screens/Login/Splash'));
import {AuthContext} from './context';
const Stack = createStackNavigator();
const StackNavigator = ({route, navigation}) => {
return (
// <NavigationContainer>
<Stack.Navigator initialRouteName="Splash">
<Stack.Screen
name="Splash"
component={Splash}
options={{headerShown: false, gestureEnabled: false}}
/>
<Stack.Screen
name="Dashboard"
component={Dashboard}
options={{headerShown: false,}}
/>
</Stack.Navigator>
);
};
export default StackNavigator;
//Here is my drawer navigator
import React, {useState,useEffect} from 'react';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '#react-navigation/drawer';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
StyleSheet,
} from 'react-native';
import {DrawerActions} from '#react-navigation/native';
import StackNavigator from './StackNavigator';
import { useNavigation } from '#react-navigation/native';
const Drawer = createDrawerNavigator()
const CustomDrawer = props => {
return (
<View style={{flex: 1}}>
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
{...props}
label="Contacts"
labelStyle={styles.itemStyle}
icon={(focused, size, color) => (
<Image
style={{width: 25, height: 25}}
source={require('../assets/images/ic_contacts1.png')}
resizeMode="contain"
/>
)}
onPress={() => {
props.navigation.closeDrawer();
}}
/>
<DrawerItem
{...props}
label="POS Catalog"
labelStyle={styles.itemStyle}
icon={(focused, size, color) => (
<Image
style={{width: 25, height: 25}}
source={require('../assets/images/catalog.png')}
resizeMode="contain"
/>
)}
onPress={() => {
props.navigation.closeDrawer();
}}
/>
</DrawerContentScrollView>
</View>
);
};
const DrawerNavigator = () => {
return (
<Drawer.Navigator
drawerContent={props => <CustomDrawer {...props} />}
screenOptions={{
drawerPosition: 'right',
// drawerType:"permanent",
headerTintColor: '#000000',
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}>
<Drawer.Screen
name="Home"
component={StackNavigator}
options={{
drawerIcon: ({focused, size}) => (
<Ionicons name="ios-home-outline" size={size} color={'#000'} />
),
headerStyle: {
backgroundColor: 'white',
},
headerShown: false,
headerTintColor: 'black',
}}/>
</Drawer.Navigator>
);
};
export default DrawerNavigator;
I have drawer and stack navigator in my react native application.I have Screens called Splash,SigninScreen,Billing and Dashboard.
Screens in navigator
Splash,Dashboard- Stack Navigator
SigninScreen,Billing-App.js file(mentioned these screens out of drawer navigator to remove drawer for these screens)
What i want to achieve is when app is opening splash screen comes first and from splashscreen i am navigating to signinscreen using navigation.replace('SinginScreen') to avaoid back navigating to splash screen again when user clicks back button in 'SigninScreen'.
Similarly i am using navigation.replace('Billing') when navigating from SigninScreen to Billing to avoid back navigating to SigninScreen again when user clicks back button in Billing.
Now Inside Billing i am using navigation.navigate('Dashboard') to navigate from Billing to Dashboard page.Here i am facing error like The action 'NAVIGATE' with payload {"name":"Dashboard"} was not handled by any navigator.
Do you have a screen named 'Dashboard'?
Note:
I want to navigate to Dashboard page from Billing and also i don't want the user to go back again billing from Dashboard.

How to use drawer for custom toolbar

Here is my drawerNavigator
import React from 'react';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
} from 'react-native';
import {DrawerActions} from '#react-navigation/native';
const Dashboard = React.lazy(() => import('../screens/Dashboard.js'));
const POSCatalog = React.lazy(() => import('../screens/POSCatalog'));
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<Drawer.Navigator
screenOptions={{
drawerPosition: 'right',
// drawerType:"permanent",
headerTintColor: '#000000',
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}>
<Drawer.Screen
name="Home"
component={Dashboard}
options={{
headerStyle: {
backgroundColor: 'white',
},
headerShown: false,
headerTintColor: 'black',
headerLeft: false,
}}
/>
<Drawer.Screen name="POSCatalog" component={POSCatalog} />
</Drawer.Navigator>
);
};
export default DrawerNavigator;
Here is my App.js file
import 'react-native-gesture-handler';
import React, {Suspense} from 'react';
import {
SafeAreaView,
Text,
View,
Button,
Image,
TouchableOpacity,
} from 'react-native';
import {
NavigationContainer,
getFocusedRouteNameFromRoute,
} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import DrawerNavigator from './navigation/DrawerNavigator';
const Dashboard = React.lazy(() => import('./screens/Dashboard.js'));
const CustomerDashboard = React.lazy(() =>import('./screens/CustomerDashboard'),);
const Splash = React.lazy(() => import('./screens/Splash'));
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Loading = () => {
return <SafeAreaView>{/* <Text>Loading</Text> */}</SafeAreaView>;
};
const Routes = ({navigation}) => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Splash">
<Stack.Screen
name="Splash"
component={Splash}
options={{headerShown: false, gestureEnabled: false}}
/>
<Stack.Screen
name="Dashboard"
component={DrawerNavigator}
options={{headerShown: false, gestureEnabled: false}}
/>
<Stack.Screen
name="CustomerDashboard"
component={CustomerDashboard}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
class App extends React.PureComponent {
render() {
return (
<Suspense fallback={<Loading />}>
<Routes />
</Suspense>
);
}
}
export default App;
Here is my Dashboard code where I am passing navigation to Banking file
import React, {useState, useEffect} from 'react';
import {
StyleSheet,
SafeAreaView,
View,
TouchableOpacity,
} from 'react-native';
import Banking from '../screens/Banking';
const Dashboard = ({navigation}) => {
return (
<SafeAreaView style={{flex: 1}}>
<View style={styles.container}>
<Banking navigation={navigation} />
</View>
</SafeAreaView>
);
};
export default Dashboard;
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
});
I am implementing navigation drawer inside my react native application and I want to access drawer wherever in my application. Let's say drawer is available in dashboard page. Inside the dashboard I have another component called banking. Inside banking I have a button to open another component called customerDashboard. In customerDashboard I have a drawer icon in toolbar. If I click drawer icon in customerDashboard I want to open the drawer.
Notes:
Drawer is available in component A
In Component A calling another component called B
Inside Component B navigating to Component C
Inside Component C need to open drawer when icon is clicked in toolbar.

Combining a stack navigator with a drawer navigator in react native

So I'm new to react native and react navigation.
I'm building an app that will have 7 main screens:
HomeScreen, ProfileScreen, CocktailDetailScreen and PublishRecipeScreen (which I want to be able to access through a drawer navigator).
LandingScreen, LoginScreen and RegisterScreen (which I don't want to show in the drawer navigator. I just want to show the LandingScreen when the user isn't logged in, and either of the other if the user want's to log in or register).
I've been able to put up a stack navigator that works fine, but I don't understand how to combine this with the drawer navigator I want. I've tried different approaches but I get errors like:
The action 'OPEN_DRAWER' was not handled by any navigator.
Is your screen inside a Drawer navigator?
or
Uncaught Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them.
This is my code so far.
App.tsx
import { SafeAreaProvider } from 'react-native-safe-area-context'
import useCachedResources from './hooks/useCachedResources'
import Navigation from './navigation'
export default function App() {
const isLoadingComplete = useCachedResources()
if (!isLoadingComplete) {
return null
} else {
return (
<SafeAreaProvider>
<Navigation />
</SafeAreaProvider>
)
}
}
(navigation) index.tsx
import { NavigationContainer } from '#react-navigation/native'
import { createNativeStackNavigator } from '#react-navigation/native-stack'
import * as React from 'react'
import LandingScreen from '../screens/LandingScreen'
import LoginScreen from '../screens/LoginScreen'
import RegisterScreen from '../screens/RegisterScreen'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'
import Header from '../components/Header'
import DrawerNavigator from '../components/DrawerNavigator'
import { RootStackParamList } from '../types'
export default function Navigation() {
const Stack = createNativeStackNavigator<RootStackParamList>()
return (
<NavigationContainer>
<Stack.Navigator >
<Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
<Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
<Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />
<Stack.Screen name='HomeScreen' component={HomeScreen} options={{ header: () => <Header/> }} />
<Stack.Screen name='ProfileScreen' component={ProfileScreen} options={{ header: () => <Header/> }} />
<Stack.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} options={{ header: () => <Header/> }} />
<Stack.Screen name='PublishRecipeScreen' component={PublishRecipeScreen} options={{ header: () => <Header/> }} />
</Stack.Navigator>
</NavigationContainer>
)
}
header.tsx
import React from 'react'
import { useNavigation } from '#react-navigation/native'
import { useDrawerStatus } from '#react-navigation/drawer'
import { DrawerActions } from '#react-navigation/native'
import { StyleSheet, Text, View } from 'react-native'
import { AntDesign } from '#expo/vector-icons'
const Header = () => {
const navigation = useNavigation()
return (
<View style={styles.container}>
<Text style={styles.title} onPress={() => navigation.navigate('RegisterScreen')}>Mixr</Text>
<View style={styles.iconContainer} >
<AntDesign name='user' style={styles.icon} size={30} color='white' onPress={() => navigation.dispatch(DrawerActions.openDrawer())} />
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#E51C27',
alignSelf: 'stretch'
},
title: {
fontSize: 40,
fontWeight: 'bold',
marginTop: 6,
marginBottom: 6,
marginLeft: 10
},
iconContainer: {
backgroundColor: 'black',
borderBottomLeftRadius: 50,
borderBottomRightRadius: 50,
borderTopLeftRadius: 50,
borderTopRightRadius: 50,
marginRight: 10
},
icon: {
padding: 5
}
})
export default Header
DrawerNavigator.tsx
import React from 'react'
import { createDrawerNavigator, useDrawerStatus } from '#react-navigation/drawer'
import { NavigationContainer } from '#react-navigation/native'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'
const DrawerNavigator = () => {
const Drawer = createDrawerNavigator()
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name='HomeScreen' component={HomeScreen} />
<Drawer.Screen name='ProfileScreen' component={ProfileScreen} />
<Drawer.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} />
<Drawer.Screen name='PublishRecipeScreen' component={PublishRecipeScreen} />
</Drawer.Navigator>
</NavigationContainer>
)
}
export default DrawerNavigator
I want to show a header in all of this pages (HomeScreen, ProfileScreen, CocktailDetailScreen and PublishRecipeScreen) and from that header be able to open/close the drawer. I don't quite understand how to link the stack navigator with the drawer.
From a more theoretical point of view, I don't really understand the difference between the stack navigator, the drawer, and other options like tab or bottom navigators.
I mean, besides that the drawer navigator shows in a drawer and the bottom one shows at the bottom. Is there a conceptual difference between them?
Full code can be found here: https://github.com/coccagerman/mixr
I think I figured it out.
What I did is nest the drawer navigator within the stack navigator.
To do so, I passed the Drawer navigator as the component of each of the screens I wanted it to be in.
Like so:
(navigation) index.tsx
import { NavigationContainer } from '#react-navigation/native'
import { createNativeStackNavigator } from '#react-navigation/native-stack'
import * as React from 'react'
import LandingScreen from '../screens/LandingScreen'
import LoginScreen from '../screens/LoginScreen'
import RegisterScreen from '../screens/RegisterScreen'
import Header from '../components/Header'
import DrawerNavigator from '../components/DrawerNavigator'
import { RootStackParamList } from '../types'
export default function Navigation() {
const Stack = createNativeStackNavigator<RootStackParamList>()
return (
<NavigationContainer>
<Stack.Navigator >
<Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
<Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
<Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />
<Stack.Screen name='HomeScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
<Stack.Screen name='ProfileScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
<Stack.Screen name='CocktailDetailScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
<Stack.Screen name='PublishRecipeScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
</Stack.Navigator>
</NavigationContainer>
)
}
And in the drawer navigator I assign the corresponding screen component to each screen:
DrawerNavigator.tsx
import React from 'react'
import { createDrawerNavigator } from '#react-navigation/drawer'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'
const DrawerNavigator = () => {
const Drawer = createDrawerNavigator()
return (
<Drawer.Navigator>
<Drawer.Screen name='Home' component={HomeScreen} options={{headerShown: false}} />
<Drawer.Screen name='Profile' component={ProfileScreen} options={{headerShown: false}} />
<Drawer.Screen name='CocktailDetail' component={CocktailDetailScreen} options={{headerShown: false}} />
<Drawer.Screen name='PublishRecipe' component={PublishRecipeScreen} options={{headerShown: false}} />
</Drawer.Navigator>
)
}
export default DrawerNavigator
I still find this a bit confusing though, and I guess there's probably a simpler way to write this.
Useful resources I've found on this topic:
https://reactnavigation.org/docs/nesting-navigators/
https://blog.waldo.io/combining-navigators-in-react-navigation/

Go from child navigation to parent navigation

I have two NavigationContainer. What I want is when I am on the SignIn screen go to the MainPage. And the problem goes when I am in MainPage > Profile. The Button Logout does not go to the SignIn Screen.
App.js
import React from "react";
import {SignIn} from './src/screen/authentication/signIn'
import {SignUp} from "./src/screen/authentication/signUp";
import {MainPage} from "./src/screen/drawer";
import {createStackNavigator} from "#react-navigation/stack";
import {NavigationContainer} from "#react-navigation/native";
const Stack = createStackNavigator();
class App extends React.Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="SignIn" headerMode={null}>
<Stack.Screen name="SignIn" component={SignIn} />
<Stack.Screen name="SignUp" component={SignUp} />
<Stack.Screen name="Home" component={MainPage} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
drawer.js
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {Dashboard} from "./dashboard/dashboard";
import {AddWidget} from "./addWidget/addWidget";
import {Profile} from "./profile/profile";
const Drawer = createDrawerNavigator();
export function MainPage({navigation}) {
return(
<NavigationContainer independent={true}>
<Drawer.Navigator>
<Drawer.Screen name="Dashboard" component={Dashboard} />
<Drawer.Screen name="Add widget" component={AddWidget} />
<Drawer.Screen name="Profile" component={Profile} initialParams={{navigation: () => navigation.navigate('SignIn')}} />
</Drawer.Navigator>
</NavigationContainer>
);
}
Profile.js
import * as React from 'react';
import {Button, Text, View} from "react-native";
import {useHistory} from "react-router-dom";
import {styles} from "./styles"
export function Profile({navigation}) {
const history = useHistory();
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>Username</Text>
<Button title="Logout" onPress={() => navigation.navigation} />
</View>
);
}
A trick that I found is printing props with console.log and finding the function inside the object.
So what I did is changing the name of initialparams from Profile, navigation to parentNaivgation. And also removing ({navigation}) to (props) in the Profile component.
At the end, the route to finding the function navigation was props.route.params.parentNavigation.navigate("SignIn")
you should be able to just do this:
<Button title="Logout" onPress={() => navigation.navigate("SignIn")} />
if the above doesn't work, you can try this:
import * as React from 'react';
import {Button, Text, View} from "react-native";
import {useHistory} from "react-router-dom";
import { useNavigation } from '#react-navigation/native';
import {styles} from "./styles"
export function Profile() {
const history = useHistory();
const navigation = useNavigation();
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>Username</Text>
<Button title="Logout" onPress={() => navigation.navigate("SignIn")} />
</View>
);
}