Switching between Stack Navigators React Native Navigation V5 - react-native

I have two steps for the user with their own Screens:
1. Login, Signup, and Enter Code (Confirmation).
I have these 3 screens as a Stack Navigator (code will be below).
2. Home, Questions, Categories.
These screens are in a different Stack Navigator.
What I want:
When the user completes the Sign in, or sign up process, they will be sent to the "Home Page". I want to switch Stack Navigators, so that the user cannot go "back" to the login screen, and also so that the Stack is cleared.
What I have tried:
I have previously used Redux to condtionially use one stack and switch after a value changes, this feels like too much work again for this functionality.
I have also tried nesting navigators, which didn't help (obviously).
Here is my StackNavigators.tsx file that contains all the stack navigators:
const Stack = createStackNavigator();
const AuthStack = createStackNavigator();
export const AuthStackNavigator = () => {
return (
<NavigationContainer>
<AuthStack.Navigator>
<AuthStack.Screen name={"Login"} component={Login} options={{
headerTitle: "Login",
headerStyle: {backgroundColor: "#eee"},
headerTintColor: GlobalStyles.darkColor
}}/>
<AuthStack.Screen name={"Signup"} component={Signup} options={{
headerTitle: "Sign Up",
headerStyle: {backgroundColor: "#eee"},
headerTintColor: GlobalStyles.darkColor
}}/>
<AuthStack.Screen name={"EnterCode"} component={EnterMfaCode} options={{
headerTitle: "Enter Code",
headerStyle: {backgroundColor: "#eee"},
headerTintColor: GlobalStyles.darkColor
}}/>
</AuthStack.Navigator>
</NavigationContainer>
)
}
export const BaseNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name={"Home"} component={Home} options={{
headerTitle: "Education",
headerStyle: {backgroundColor: "#eee"},
headerTintColor: GlobalStyles.darkColor
}}/>
<Stack.Screen name={"Questions"} component={Questions} options={{
headerStyle: {backgroundColor: "#eee"},
headerTintColor: GlobalStyles.darkColor,
headerTitle: "",
gestureEnabled: false,
headerBackTitle: "Categories"
}}/>
<Stack.Screen name={"Categories"} component={Categories} options={{
headerStyle: {backgroundColor: "#eee"},
headerTintColor: GlobalStyles.darkColor,
headerTitle: "",
headerBackTitle: "Start"
}}/>
</Stack.Navigator>
);
};
I would be very thankful if an explanation for how to approach this issue would be. I Appreciate the time!

I feel like using Redux is a good and straight forward solution. Another option is to use LocalStorage to store some value and just take it from there.
As I want the user to be loggedIn after closing the application, I found that using LocalStorage + Redux feels like a great solution.
You can red more on this documentation on how to handle everything.
https://reactnavigation.org/docs/auth-flow

Related

open mobile app from browser app using react-native on expected route

So in my browser app i'm using window.location.replace('scheme://') and this one successfully open the mobile application and from there issues starts.
Is not open on the expected screen i have the following Navigator Structure
Main Stack
const linking = {
prefixes: ['scheme://'],
config: {
screens: {
TabNavigator: {
initialRouteName: Routes.ACCOUNT_SETTINGS_SCREEN,
screens: {
AccountSettingsScreen: {
path: Routes.ACCOUNT_SETTINGS_SCREEN,
},
},
},
},
},
};
<NavigationContainer linking={linking}>
<Stack.Navigator initialRouteName={initRoute} screenOptions={{ headerTitle: '', headerShown: false }}>
<Stack.Group>
<Stack.Screen name={Navigators.TAB_NAVIGATOR} component={TabNavigator} />
<Stack.Group>
</Stack.Navigator>
</NavigationContainer>
Bottom Tabs
<Tab.Navigator
screenOptions={{
headerShown: false,
}}
>
<Tab.Screen name={Routes.ACCOUNT_SETTINGS_SCREEN} component={AccountSettingsScreen} options={{ tabBarLabel: 'Items', tabBarIcon: ItemsIcon }} />
</Tab.Navigator>
and my linking object
I don't manage to open Account settings screen, it's always home screen of the application.

How to avoid the suddenly chop down on react native navigator

Here is the code I got:
I got a Stack Navigator that store two screens:
<Stack.Navigator
initialRouteName="FirstScreen"
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="FirstScreen" component={FirstScreen}/>
<Stack.Screen name="DrawerNavigator" component={DrawerNavigator}/>
</Stack.Navigator>
And I got a DrawerNavigator which have my MainNavigator, which is the screen cap I provided:
<Drawer.Navigator
initialRouteName="MainNav"
screenOptions={{
drawerStyle: {
backgroundColor: getPrimaryColor()
},
drawerLabelStyle: {
color: 'white'
}
}}>
<Drawer.Screen
name="MainNav"
component={MainNav}
options={({route}) => (getShowOptions(route))}/>
</Drawer.Navigator>
Inside the MainNav, it have two page, one is home, another is detail:
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
options={{ headerShown:false }}
name="Home"
component={Home}
/>
<Stack.Screen
name="Detail"
component={Detail} />
</Stack.Navigator>
As you may noticed that it has a getShowOptions method, which is control the actual nav bar display:
function getShowOptions(route) {
const routeName = getFocusedRouteNameFromRoute(route);
const icon =
let options = {
headerStyle: {
backgroundColor: getPrimaryColor()
},
headerTintColor: '#fff',
headerTitleAlign: 'center',
title: i18n.t('Home'),
drawerIcon: ({focused, size}) => (
<View
style={[{
height: iconSize,
width: iconSize
}
]}>
{icon}
</View>
)
};
if (routeName === 'Detail') {
options.headerShown = false;
}
return options;
}
When the screen is push to "Detail", it will hide the header, to show a header that have a back button, but when it put back to "Home", it should use back the "Drawer" menu button. As u can see the issue happen when we switch back and forward between the drawer navigation bar and the stack navigation bar.
The use case is pretty simple, we would like to have the "menu" when the "home" screen is appear, and "back" appear when the "detail" screen is presented. It seems that the React Native Stack Navigator and Drawer Navigator can't work together very well. Any suggestions?

How to navigate to a another screen in class component in react native

App.js code:
function firstScreenStack({ navigation }) {
return (
<Stack.Navigator initialRouteName="Login">
<Stack.Screen
name="Login"
component={Login}
options={{
title: 'Login', //Set Header Title
headerLeft: ()=>
<NavigationDrawerStructure
navigationProps={navigation}
/>,
headerStyle: {
backgroundColor: '#CA2C68', //Set Header color
},
headerTintColor: '#fff', //Set Header text color
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}
/>
</Stack.Navigator>
);
}
function secondScreenStack({ navigation }) {
return (
<Stack.Navigator
initialRouteName="Browse"
screenOptions={{
headerLeft: ()=>
<NavigationDrawerStructure
navigationProps={navigation}
/>,
headerStyle: {
backgroundColor: '#CA2C68', //Set Header color
},
headerTintColor: '#fff', //Set Header text color
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
}
}}>
<Stack.Screen
name="Browse"
component={Browse}
options={{
title: 'Browse', //Set Header Title
}}/>
<Stack.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile', //Set Header Title
}}/>
</Stack.Navigator>
);
}
export default App function has below code:
<NavigationContainer>
<Drawer.Navigator
initialRouteName = {Login}
drawerContentOptions={{
activeTintColor: '#CA2C68',
itemStyle: { marginVertical: 5 },
}}>
<Drawer.Screen
name="Login"
options={{ drawerLabel: 'Login' }}
component={firstScreenStack} />
<Drawer.Screen
name="Browse"
options={{ drawerLabel: 'Browse' }}
component={secondScreenStack} />
<Drawer.Screen
name="Profile"
options={{ drawerLabel: 'Profile' }}
component={profileScreenStack} />
</Drawer.Navigator>
</NavigationContainer>
I am using stack and drawer navigation both.
I want navigation.navigate("Profile");
Now how can I get navigation props into my class components? I am new in react native and navigation. Its bit complicated to understand for me. If you can help me out it will be better. Thanks.
If we are supposed to navigate from the screen of the first stack navigator to another navigator then we have to access the parent of the first navigator's screen, which mean we have to get the navigation prop of the first stack navigator as we have created a drawer based on the multiple screens.
fox ex. if you want to navigate from the Browse screen of firstScreenStack to another drawer screen navigator then have a try with the below code:
if using Class Component:
this.props.navigation.dangerouslyGetParent()?.navigate("<<ANOTHER_DRAWER_SCREEN>>")
if using Functional Component:
props.navigation.dangerouslyGetParent()?.navigate("<<ANOTHER_DRAWER_SCREEN>>")
Navigation is accessible in stack routes only i.e, those classes or components which are used as routes in different navigators.
Now if i got your question, you want to access it in all components irrespective of whether it is a route or not. You can do that by passing props to it from a component which is a route.
E.g,
Let main be a route and child be another component but not a route.
Inside the main;
<child new_navigation={this.props.navigation} />
Now you can access the new_navigation inside the child.
Inside the child;
this.props.new_navigation.navigate('some_route') //you can now use all the other methods also like push, replace etc.

React Native Navigation v5 bottom navigation navigate to new stack

Learning React Native and I've run into a navigation issue using createBottomTabNavigator.
I have my screen displayed with 2 links on the bottom tab. Link 1 - Novels, Link 2 - Profile.
When I click on Link 2, I want to go to my profile screen (which it does) but I want to replace the bottom tab with a new one (which it doesn't).
I've tried using the tabPress event and I can see using console.log that it catches the event, but when I add the navigation param it stops working.
here's the relevant code:
const Stack = createStackNavigator();
const BottomTab = createBottomTabNavigator();
const headerTitle = "My Title";
function NovelsStack() {
return (
<Stack.Navigator screenOptions={{
headerStyle: {
backgroundColor: '#000',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
fontSize: 16,
},
}}>
<Stack.Screen name="Home" component={HomeScreen} options={{ headerTitle: () => <HeaderTitle title={headerTitle} /> }} />
<Stack.Screen name="Novels" component={TabNavigation} options={{ headerTitle: () => <HeaderTitle title={headerTitle} /> }} />
<Stack.Screen name="Novel" component={SelectedNovelNavigation} options={{ headerTitle: () => <HeaderTitle /> }} />
<Stack.Screen name="Profile" component={ProfileNavigation} options={{ headerTitle: () => <HeaderTitle title={headerTitle} /> }} />
</Stack.Navigator>
);
}
function TabNavigation() {
return (
<BottomTab.Navigator
tabBarOptions={{
labelStyle: styles.mainTabBarLabels
}}
>
<BottomTab.Screen name="Novels" options={{ title: "Novels" }} component={NovelsScreen} />
{isAuthenticatedUser() ? (<BottomTab.Screen name="Profile" component={ProfileScreen} />)
: (<BottomTab.Screen name="Login" component={LoginScreen} listeners={({ navigation, route }) => ({
tabPress: e => {
// Prevent default action
console.log(navigation)
e.preventDefault();
},
})} />)
}
</BottomTab.Navigator>
);
}
function ProfileNavigation() {
return (
<BottomTab.Navigator
tabBarOptions={{
labelStyle: styles.novelsTabBarLabels
}}>
<BottomTab.Screen name="Profile" component={ProfileScreen} options={{ title: "Profile" }} />
</BottomTab.Navigator>
);
}
function SelectedNovelNavigation() {
return (
<BottomTab.Navigator
tabBarOptions={{
labelStyle: styles.novelsTabBarLabels
}}>
<BottomTab.Screen name="Novel" component={NovelScreen} />
<BottomTab.Screen name="Comments" component={CommentsScreen} options={{ title: "Comments" }} />
<BottomTab.Screen name="Ratings" component={RatingsScreen} options={{ title: "Ratings" }} />
<BottomTab.Screen name="Related" component={RelatedNovelsScreen} options={{ title: "Related" }} />
</BottomTab.Navigator>
)
}
What I want to happen is when the user presses the "Profile" tab on the TabNavigation Stack, that the navigation takes the user to show the ProfileNavigation where I can add additional profile tabs, but I just can't get that hooked up correctly. Been looking at the docs and other posts about it, but still stuck.
Thanks in advance for any help
As usual, once you reach out for help you get the answer. In the docs here (https://reactnavigation.org/docs/bottom-tab-navigator/) and here (https://reactnavigation.org/docs/stack-actions/#replace) I can customize the tabBar and use the navigation.replace.
The good ole docs, I was all around it, just didn't see it.

Dynamic Title change on the screen

I have a navigation code:
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name='Home' component={Home} options={{ headerShown: false }} />
<Stack.Screen name='Learning' component={Learning}
options={{
headerTransparent: true,
title: 'Learning',
headerTitleAlign: 'center',
}} />
</Stack.Navigator>
</NavigationContainer>
I use the Learning screen for two functional application screens:
A
B
On screen A, I have two buttons:
<TouchableOpacity onPress={() => navigation.navigate('Learning', { screen: 'Learning' })}/>
<TouchableOpacity onPress={() => navigation.navigate('Learning', { screen: 'Repeats' })}/>
Depending on this content, {screen: 'Learning'} is loading some other data
This screen has a title header
How do you make it load a different title depending on the button you click?
I can't find a solution how to do it for Components built on functions and Hooks
The options prop can take a function and provide {route, navigation} object as an argument for you, so to use the params in the header, you can do this:
<Stack.Screen
name="Learning"
component={Learning}
options={({ route }) => ({ title: route.params.screen })}
/>
I'm not sure what difference the functional components and hooks make in this case, but in case I misunderstood the question, you can use useNavigation and useRoute hooks in your functional components and do the same things that you do in classes.