How to reset react navigation when "unmounting" from a tab? - javascript

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>
);
};

Related

How to prompt a Screen before going into Navigation Root in React Native?

I am in my AppRoot and am trying to implement a subscription paywall screen, that will be prompted when the loading of the app is done if the user is not subscribed, but will continue with the regular flow if the user is subscribed. Here is the return of my approot currently.
return (
<SettingsProvider>
{ ({ isLoading }) => (
(isLoading || !isLoadingComplete) ? (
<KeepSplashScreen/>
) : (
<PaperProvider theme={theme}>
<SafeAreaProvider>
/// prompt subscription screen here??
<NavigationRoot />
</SafeAreaProvider>
</PaperProvider>
)
)}
</SettingsProvider>
);
I was thinking of using a navigation stack or something similar to show the screen here based on a status such as
const status = true
What would be the best route to approach this?
I've tried putting in a stack
<Stack.Screen
name="Subscreen"
component={SubScreen}
initialParams={{ initialroute: 'Home' }}
/>
But I'm not sure if this is the way to do it?

Wrong back button behavior in react native

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/

How to conditionally render a screen in React native but place it on to stack?

I have this:
const initialRouteName = leagueId ? 'League' : 'Leagues'
return (
<Stack.Navigator initialRouteName={initialRouteName}>
<Stack.Screen
name="Leagues"
>
{(props: any) => <MyLeagues navigation={props.navigation} theme={theme} />}
</Stack.Screen>
<Stack.Screen
name="League"
>
{(props: any) => {
return <League leagueId={leagueId} theme={theme} />
}}
</Stack.Screen>
</Stack.Navigator>
now this works (sort of). I've changed this behaviour that when I use PNs if the leagueId exists, then it will "navigate" the user to the correct screen.
however, the behaviour use to be if you clicked on the tab where this stack is initiated it would go back to the Leagues screen. it doesn't do that now as I've set the initialRouteName to be League, so I guess Leagues isn't on the stack. is there a way to make sure I render League screen initially if leagueId exists but also allow it to go back? if that makes sense

React Native: Tab and Stack Navigation Integrited

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.

Passing Params from Stack-navigator to tab Navigator (react-navigation 5)

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

Categories