React Native Tab Navigator within Stack Navigator - react-native

I have the following Stack Navigator in App.js:
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Login" screenOptions={{headerShown:false}}>
{user ? (
<>
<Stack.Screen name="Home">
{(props) => <HomeScreen {...props} extraData={user} />}
</Stack.Screen>
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
</>
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Registration" component={RegistrationScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
);
I want to add a bottom tab navigator that shows up on the HomeScreen, and allows me to go back and forth between the HomeScreen and ProfileScreen. How can this be done?

The way to do this is to create a tab navigator component where Home and Profile are 2 screens of the navigator:
const Tab = createBottomTabNavigator();
function TabNavigator({route}) {
// Retrieve user from initalParams.
// The user is passed to initialParams in the snippet below.
const user = route.params?.user
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
Then the tab navigator can be a screen of your stack navigator:
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Login"
screenOptions={{headerShown: false}}>
{user ? (
<>
<Stack.Screen name="Tabs" component={TabNavigator} initialParams={{user: user}}/>
</>
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Registration" component={RegistrationScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
);
If you need access to user from inside HomeScreen you can pass it using down using initialParams the same way it was passed down to the TabNavigator. If you don't want to keep passing stuff down like this you could try the Context api.
I removed the Login screen in the above example, because I assumed this was a mistake as you already have a Login screen defined for when you don't have an authenticated user.

Related

How do I nest my tab navigator with my stack navigator in react native?

Good evening,
I successfully created a project inside react native now I would like to nest my tab navigator with my stack navigator. I'm getting errors when I put my tab navigator with the stack navigator. My tab navigation code is:
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Earnings" component={EarningsScreen} />
</Tab.Navigator>
);
}
function Root() {
return (
<NavigationContainer>
<MyTabs/>
</NavigationContainer>
);
My stack navigator code is:
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Notifications" component={NotificationsScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}
It looks like you're using two separate NavigationContainers, and you're not nesting the navigators at all; the code for each is completely separate.
Given that your question is about needing the tabs within the stack, try this instead:
delete the Root component (you should only have one NavigationContainer in your app)
use the MyTabs component as one of your stack screens
Example:
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Earnings" component={EarningsScreen} />
</Tab.Navigator>
);
}
function MyStack() {
return (
<Stack.Navigator>
{/* Tabs are inserted here */}
<Stack.Screen name="Tabs" component={MyTabs} />
<Stack.Screen name="Notifications" component={NotificationsScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}

How do I go from the screen in the navigator to the screen in the other navigator?

function Logins() {
return (
<Provider theme={theme}>
<Stack.Navigator
initialRouteName="StartScreen"
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="StartScreen" component={StartScreen} />
<Stack.Screen name="LoginScreen" component={LoginScreen} />
<Stack.Screen name="RegisterScreen" component={RegisterScreen} />
<Stack.Screen name="Dashboard" component={Dashboard} />
<Stack.Screen
name="ResetPasswordScreen"
component={ResetPasswordScreen}
/>
</Stack.Navigator>
</Provider>
)
}
function Drawers() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Profile" component={UnderConstruction} />
<Drawer.Screen name="Popular" component={UnderConstruction} />
<Drawer.Screen name="Saved" component={UnderConstruction} />
<Drawer.Screen name="Discover" component={UnderConstruction} />
<Drawer.Screen name="Configuration" component={UnderConstruction} />
<Drawer.Screen name="Help Center" component={UnderConstruction} />
</Drawer.Navigator>
)
}
function Main() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Search" component={Search} />
<Stack.Screen name="Notification" component={Notification} />
<Stack.Screen name="Message" component={Message} />
</Stack.Navigator>
)
}
function Detail() {
return (
<Stack.Navigator>
<Stack.Screen name="Tweet" component={UnderConstruction} />
<Stack.Screen name="New Tweet" component={TweetButton} />
<Stack.Screen name="New Message" component={UnderConstruction} />
<Stack.Screen name="DynamicTitle" component={UnderConstruction} />
</Stack.Navigator>
)
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Logins"
screenOptions={{
headerMode: 'none',
}}
>
<Stack.Screen name="Logins" component={Logins} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Drawer" component={Drawers} />
<Stack.Screen name="Details" component={Detail} />
</Stack.Navigator>
</NavigationContainer>
)
}
As you can see, I made a stack navigator that contains all the stack navigators, logins, main, drawers, and details.
And I want to make it possible to move between Home and New Tweet, which belong to different navigators.
I tried this.props.navigation.navigate ("New Tweet")
and this.props.navigation.navigate ("Details", {screen: "New tweet"}) inside the components on the Home screen.
But both didn't work and I got an error "NAVIGATE" with payload {"name": "New tweet"} was not handled by any navigator.
I think it's because they're different navigators. But I don't know how to do..
Change Detail to Details and New tweet to New Tweet. Try following
this.props.navigation.navigate ("Details", {screen: "New Tweet"})
I think there is no way directly to switch to a different stack navigator if they are not related to each other. From here I think this can be one option
Make the screen available in the stack that you want to switch from the home screen. For example, in the main function, if you want to switch to "detail" screen
function Main()
{
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Search" component={Search} />
<Stack.Screen name="Notification" component={Notification} />
<Stack.Screen name="Message" component={Message} />
<Stack.Screen name="Details" component={Detail} />
</Stack.Navigator>)
}
now from here your homescreen you can call this.props.navigation.navigate ("Details", {screen: "New Tweet"})
You can also look into the below thread to achieve this otherway around
React Navigation 5: Switching between different stack navigators in React native

How to enable Drawer Navigation only on specific screen (e.g. Home Screen) [react native] [react navigation]

Use case of this problem is to have Drawer menu like "Settings" available only form "Home Screen". And at "Home screen" could be many buttons that link to other screens of Stack Navigation where Drawer is not available.
Main question is how to enable Drawer Navigation only on specific screen of Stack Navigator?
On below example Drawer is available on all pages of Stack. I tried with gestureEnabled but it didn't work:
const StackHome = () => (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Example1" component={Example1} />
<Stack.Screen name="Example2" component={Example2} />
</Stack.Navigator>
);
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={StackHome} />
<Drawer.Screen name="Settings" component={Settings} />
</Drawer.Navigator>
On the other hand if I try make Drawer as one of Stack screen, then I have always the same Header bar (example "Header")
Put your drawer navigator inside the home screen:
const DrawerHome = () => (
<Drawer.Navigator screenOptions={{ headerShown: true }}>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Settings" component={Settings} />
</Drawer.Navigator>
);
const StackHome = () => (
<Stack.Navigator>
<Stack.Screen
name="DrawerHome"
component={DrawerHome}
options={{ headerShown: false }}
/>
<Stack.Screen name="Example1" component={Example1} />
<Stack.Screen name="Example2" component={Example2} />
</Stack.Navigator>
);

React Native Stack Navigation Screen Doesn't Exist

In App.js I have the following Stack Navigator:
<NavigationContainer>
<Stack.Navigator>
{user ? (
<Stack.Screen name="Home">
{(props) => <HomeScreen {...props} extraData={user} />}
</Stack.Screen>
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Registration" component={RegistrationScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
In the HomeScreen, I am trying to navigate to the "Profile" screen:
export default function HomeScreen(props) {
const onProfilePress = () => {
props.navigation.navigate('Profile')
};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={onProfilePress}>
<Text style={styles.buttonText}>Profile</Text>
</TouchableOpacity>
</View>
);
}
However, I get a
The action 'NAVIGATE' with payload {"name":"Profile"} was not handled by any navigator.
Does anyone know how to fix?
Profile is only part of the stack when user is true.
Perhaps you meant to do something like this:
<NavigationContainer>
<Stack.Navigator>
{user ? (
<>
<Stack.Screen name="Home">
{(props) => <HomeScreen {...props} extraData={user} />}
</Stack.Screen>
<Stack.Screen name="Profile" component={ProfileScreen} />
</>
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Registration" component={RegistrationScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>

ReactNative- Tab Navigator Inside Stack Navigator

Need to Show Tabs For Home Module after Signup Module
using React-navigation
Working Code with Only Stack Screens
const Stack = createStackNavigator();
const Bottom = createBottomTabNavigator();
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Welcome" headerMode='none' >
<Stack.Screen name="Welcome" component={WelcomeScreen}
options={{
title: '',
headerBackTitleVisible: false,
headerBackTitle: '',
headerShown: true
}}
/>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Signup" component={SignupScreen} />
<Stack.Screen name="ResetPassword" component={ResetPasswordScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Need to show Tab from SigninScreen Button
Tab 1: Dashboard:
Tab 2: Profile
Tried Code:
<Bottom.Navigator initialRouteName="Dashboard" >
<Bottom.Screen name="Dashboard" component={TabDashboard} />
<Bottom.Screen name="Profile" component={TabProfile} />
</Bottom.Navigator>
Now I need to combine these two block of codes so I can navigate to Tabs
Tab screen will have further navigations
The idea would be to wrap the tabs screen inside component and add it to the stack conditionally.
const HomeScreen = () =>{
return (
<Bottom.Navigator initialRouteName="Dashboard" >
<Bottom.Screen name="Dashboard" component={TabDashboard} />
<Bottom.Screen name="Profile" component={TabProfile} />
</Bottom.Navigator>
);
}
Your stack should change as below
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Welcome" headerMode='none' >
{
this.state.isSignedIn ? (
<>
<Stack.Screen name="Welcome" component={WelcomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Signup" component={SignupScreen} />
<Stack.Screen name="ResetPassword" component={ResetPasswordScreen} />
</>
) : (
<>
<Stack.Screen name="ResetPassword" component={HomeScreen} />
</>
)
}
</Stack.Navigator>
</NavigationContainer>
);
}
IsSignedIn can be the state variable or a variable that you store the logged in status
You can refer the authentication flows
https://reactnavigation.org/docs/auth-flow