I have an issue with Tab Navigation and Stack.
The following is Stack and Tab Navigation:
export function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Home"
activeColor={COLORS.white}
barStyle={{ backgroundColor: COLORS.mediumgrey }}
inactiveColor={COLORS.grey}>
...
<Tab.Screen
name="More"
component={MoreStack}
options={{
tabBarLabel: <Text style={styles.bottomNavBarTextSize}>More</Text>,
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="settings" color={color} size={26} />
)
}
} />
The component "MoreStack" is a stack Navigation which is the following:
function MoreStack() {
return (
<Stack.Navigator
initialRouteName="More"
screenOptions={{
headerStyle: { backgroundColor: COLORS.mediumgrey },
headerTintColor: COLORS.white,
headerTitleStyle: styles.navBarTitleFont
}}>
<Stack.Screen name="More" component={MoreScreen} options={{ headerShown: false }} />
...
<Stack.Screen name="Login" component={Login} options={{ headerShown: false }} />
</Stack.Navigator>
);
}
In MoreScreen Page, I have the following logout code:
logOut = () => {
firebase.auth().signOut().then(() => {
this.props.navigation.replace('Login')
});
}
The issue I have is that it does go to the login page but the bottom navigation bar does NOT go away. And if I want to go back, then it goes back to the MoreScreen which it shouldn't. Logically, once you logout, you should not be able to go back.
The following picture shows the issue
Notice how the bottom navigation bar is still there and if the back button is clicked, it goes back to the previous screen
****UPDATE
FIXED: I fixed it by combining all the stacks into 1. It would not work if you want to do STACK1>MyTabs>STACK2. Fixed it by doing STACK1>MyTabs>Stack1.
Think about it this way, you have a Tab Navigation, Stack navigation and a Login Screen. Your parental status of your navigations is Tab Nav > Stack Nav > Login Screen. So when you are in any screen in your Stack Nav, you are going to be seeing the Tabs. What you need to do is the opposite.
Put your Tab Nav into a Stack navigator and name it App Navigator. And create another Stack Nav and name it CredentialNavigator, and put your Login/Signup screen into it. And in your Main/Root navigation file, you can dynamically render either your CredentialNavigator or AppNavigator based on your Login State.
isLogged ? false return <CredentialNavigator/> : return <AppNavigator>
This is very simple of course, but you can definitely expand this tree. I suggest you to go through almost all React Navigation 5 docs, it is very easy to follow and very informative.
Related
Tried these two ways, but none worked:
options={{
headerLeft: () => {
return null}
}}
// method 2
screenOptions={{
headerLeft: null,
}}
You could do it for all screens or for one of them like so:
<Stack.Navigator
// For all screens inside this Stack Navigator
screenOptions={{
headerBackVisible: false,
}}
>
<Stack.Screen
// For the login screen inside this Stack Navigator
options={{ headerBackVisible: false }}
component={LoginScreen}
name="Login"
/>
</Stack.Navigator>
guys I have a question about navigation in react native.
So I mainly use TabNavigator. I have 2 main stack navigators in the app
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Profile" component={ProfileStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
In my ProfileStack screen, I have also two pages: MyProfile and UsersProfile:
const ProfileStack = createNativeStackNavigator();
function ProfileStackScreen({route, navigation}) {
return (
<ProfileStack.Navigator initialRouteName="MyProfile">
<ProfileStack.Screen name="MyProfile" component={MyProfilePage} />
<ProfileStack.Screen name="UserProfile" component={UserProfilePage} options={{
headerLeft: () => (<View>
<Button title="back" onPress={() => {navigation.goBack()}}/>
</View>)
}}/>
</ProfileStack.Navigator>
);
}
Now I want to navigate from the HomeScreen to the UserProfilePage and pass params to this screen. I'm doing it like this:
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home screen this</Text>
<Button
title="Go to another user profile"
onPress={() => navigation.navigate('Profile', {screen: 'UserProfile', params: {userId: 1235}})}
/>
</View>
);
}
So now, when I come to the page UserProfile I see that it loads also the Profile page, and just for a second I see blinking of ProfilePage and its UI that is not cool, and should it be like so? I guess not.
Then if I press the BACK button on UsersProfilePage, I'm navigating back to HomeScreen - and this is ok! This is what I expect!
But now, If I will press ProfileTab I see only UsersProfilePage but not MyProfilePage. When I press the BACK button again, I go back to the HomeScreen that is weird for me. Can u explain why it happens? Why I don't get back to the MyProfilePage.
I prepared an expo snack here. You can reproduce this behavior.
This is because you’re navigating to a screen in a nested navigator. It is ignoring the initial route. Then when you press the tab again it is still mounted and will still have the previous route state, which is just the screen without the initial screen.
By default, when you navigate a screen in the nested navigator, the specified screen is used as the initial screen and the initial route prop on the navigator is ignored. This behaviour is different from the React Navigation 4.
If you need to render the initial route specified in the navigator, you can disable the behaviour of using the specified screen as the initial screen by setting initial: false:
navigation.navigate('Root', {
screen: 'Settings',
initial: false,
});
See https://reactnavigation.org/docs/nesting-navigators/#rendering-initial-route-defined-in-the-navigator and https://reactnavigation.org/docs/navigation-lifecycle/
I am developing an app which has bottom tab navigation. For implementing this , I've used react-navigation-material-bottom-tabs, which is working perfectly fine. Like I have 3 screens ,say Home, Profile and About in the bottom tab navigator. But in the Home screen I have multiple screens flow to be implemented. For that I used Stack Navigator, which is also working fine. So my app flow is like Home-> Screen1-> Screen2-> Screen3 Where I'm facing problem is that suppose I'm on Screen3 and then I switch to Profile screen from bottom navigation, and then again switch to Home screen.
I should be able to see Home Screen there but currently it shows Screen3
Following is my code:
MainTabs.js
import { createStackNavigator } from '#react-navigation/stack';
import Icon from 'react-native-vector-icons/Ionicons';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
const HomeStack = createStackNavigator();
const ProfileStack = createStackNavigator();
const AboutStack = createStackNavigator();
const HomeStackScreen = ({ navigation }) => {
return (
<HomeStack.Navigator screenOptions={{headerShown: false, initialRouteName: 'Screen1'}}>
<HomeStack.Screen name="Screen1" component={Screen1} />
<HomeStack.Screen name="Screen2" component={Screen2} />
<HomeStack.Screen name="Screen3" component={Screen3}/>
</HomeStack.Navigator>
)
}
const ProfileStackScreen = ({ navigation }) => {
return (
<ProfileStack.Navigator screenOptions={{headerShown: false, initialRouteName: 'Profile'}}>
<ProfileStack.Screen name="Profile" component={Profile} />
</ProfileStack.Navigator>
)
}
const AboutStackScreen = ({ navigation }) => {
return (
<AboutStack.Navigator screenOptions={{headerShown: false, initialRouteName: 'About'}}>
<AboutStack.Screen name="About" component={About} />
</AboutStack.Navigator>
)
}
const MainTabScreen = () => {
return (
<Tab.Navigator
initialRouteName="Home"
activeColor="#fff"
barStyle={{ backgroundColor: 'red' }}
labeled={false}
>
<Tab.Screen
name="Home"
component={HomeStackScreen}
/>
<Tab.Screen
name="Profile"
component={ProfileStackScreen}
/>
<Tab.Screen
name="About"
component={AboutStackScreen}
/>
</Tab.Navigator>
);
export default MainTabScreen;
Use navigation.navigate('routeName') when you tap on your bottom tab navigator element. You have to register a route to the first screen of the stack, and from there you can go inside the stack as you like.
set unmountOnBlur options to true.
If you don't mind this.
Normally, we don't recommend enabling this prop as users don't expect their navigation history to be lost when switching tabs. If you enable this prop, please consider if this will actually provide a better experience for the user.
Another way is to pop the stack navigator when leaving screen3.
so I have a stack named AuthStack like so
const AuthStack = ({ resetPassword, updateEmail }: any) => (
<Stack.Navigator
screenOptions={{
cardStyle: { backgroundColor: '#F2F1F7' },
headerShown: true,
headerTitle: '',
}}
>
{resetPassword ? (
<Stack.Screen name="Reset Password">{(props: any) => <ResetPassword />}</Stack.Screen>
) : updateEmail ? (
<Stack.Screen name="Update Email">{(props: any) => <UpdateEmail />}</Stack.Screen>
) : (
<Stack.Screen name="Home">{(props: any) => <Home />}</Stack.Screen>
)}
</Stack.Navigator>
)
would be good to know if this is the right way to do it. but essentially from my account page I have links to reset password and update email. I put both these in the AuthStack as I wasn't sure if this was the best place. anyway this sort of works, however if I click on "update email" and get navigated to there, if I then decide actually I want to go to another page and navigate away, if I then navigate back by clicking on "Home", it takes me to the update email page still. even though I really want to show the home screen at this point. also if I click on home whilst it's active it doesn't take me there. thus meaning I can never see my home page again.
so I was wondering if there is some sort of listener that when I navigate away from this page it will alway show me Home by default?
any ideas? and I don't want to show reset password /update email as there own tabs hence hiding them under home. is there a better approach for this?
I really don't know why you are conditionally render the screens, I think you are using name in bad way. You should navigate like navigation.navigate('ForgotPassowrd') (name of the screen). It keep showing you update email because Home not exist.
export const AuthNavigator = () => {
return (
<Stack.Navigator headerMode='none'>
<Stack.Screen name='Home' component={SignupContainer}></Stack.Screen>
<Stack.Screen name='ForgotPassword' component={ForgotPasswordContainer}></Stack.Screen>
<Stack.Screen name='Update Email' component={UpdateEmailContainer}></Stack.Screen>
</Stack.Navigator>
);
};
I am trying to pass the user ID from the login screen to the home screen which is part of a nested tab navigator.
here is how my app is structured:
const mainStack = () =>(
<Tab.Navigator
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
}}
>
<Tab.Screen name="Home" component={Homescreen}
options = {{headerStyle: {backgroundColor: 'yellow'}}}
/>
<Tab.Screen name="Profile" component={otherStack} />
</Tab.Navigator>
)
export default () => (
<NavigationContainer >
<Stack.Navigator screenOptions={{
headerShown: false
}}>
<Stack.Screen name='Welcome' component={WelcomeScreen} />
<Stack.Screen name = 'Register' component = {RegisterScreen} />
<Stack.Screen name= 'Login' component={LoginScreen} />
<Stack.Screen name = 'mainStack' component={mainStack} />
</Stack.Navigator>
</NavigationContainer>
)
Whenever I go from the login screen to Home and call this.props.navigation.getParam('id') I get an error saying that it is not a function. After closer inspection I see that this.props.navigation.state is undefined. Probably meaning that my params aren't passed to the Home screen even though I don't have any issues navigating to it.
I tried using NavigationActions but I get an error that I don't see mentioned anywhere else.
I navigate to Home like this:
this.props.navigation.navigate('Home' { id: 'myId' })
I also tried this syntax:
navigation.navigate('Root', {
screen: 'Settings',
params: { user: 'jane' },
});
but I get the same error
It is also worth noting that I used React.component rather than making my screens into functions. I am not sure if that causes any issues because in the tutorial for react-navigation v5 I saw the guy use functions instead of react components.
any help will be very much appreciated!!
Try this:
props.navigation.navigate('mainStack' { params: {id: 'myId'}, screen: 'Home' )
And when accessing instead of using getParam use props.route.params.id