Remove navigation stack for login screen after user login - react-native

I am new to React Native. I am so confused about navigation stack.
Here is my code.
const AppNavigator = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} options={{ title: 'login' }}/>
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'home' }}/>
</Stack.Navigator>
</NavigationContainer>
);
};
Users will see the login screen once they run this app.
And here is LogInScreen.
const LogInScreen = ({ navigation }) => {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="google login"
onPress={() =>
navigation.navigate('Home')
}
/>
</View>
);
};
Users is going to see home screen after they clicked login button.
But the problem is they still can see back button in home screen.
After log in , it's not necessary to show login screen to users.
Hence, I need to reset stack to remove back button in home screen.

If you want to remove the back button in the home screen, you can use the headerLeft option as specified here.
I think it is enough if you're developing for iOS. For Android, the user can still use the back button to go back. I think resetting the stack and navigate the user the home page is also a good solution. You can look into this post

Related

Splash screen won't move on to next screen after user signup on react navigation 6

My React Native 0.66.1 app (on Big Sur/iPhone simulator) has a SplashScreen for reading local data. After splash screen, navigation moves to AppScreen which decides which screen to show next. The app uses React Navigation 6.x for navigation.
"#react-navigation/native": "^6.0.6",
"#react-navigation/stack": "^6.0.11",
In AppScreen, if the local data loaded in splash screen is valid and success, then it will show the Home screen, if not, then show 'Signup' screen to let user to signup. After user signs up, then navigation goes to splash screen again to read the local data. Here is view portion of AppScreen.js:
import { createStackNavigator } from '#react-navigation/stack';
const AStack = createStackNavigator();
......
return(isLogin ? (
<propsContext.Provider value={propsVal}>
<authContext.Provider value={authVal}>
<stateContext.Provider value={stateVal}>
<AStack.Navigator initialRouteName="Home">
<AStack.Screen name="Home" component={Home} options={{headerLeft:false}}/>. //<<===Home Screen after splash screen when user signs up
<AStack.Screen name="Verif1" component={Verif1} options={{title:'验证'}} />
<AStack.Screen name="Signup" component={Signup} options={{title:'我贴吧',
headerStyle: {backgroundColor: '#f4511e',},
headerTitleStyle: { alignSelf: 'center' },
headerTintColor: '#fff',
headerShown:true}} />
<AStack.Screen name="Splash" component={SplashScreen} options={{headerShown:false}}/>
<AStack.Screen name="AppScreen" component={AppScreen} options={{headerShown:false}} />
</AStack.Navigator>
</stateContext.Provider>
</authContext.Provider>
</propsContext.Provider>
) : (
<propsContext.Provider value={propsVal}>
<authContext.Provider value={authVal}>
<stateContext.Provider value={stateVal}>
<AStack.Navigator initialRouteName="Signup">. //<<== Signup screen after splash screen if login failed
<AStack.Screen name="Verif1" component={Verif1} options={{title:'验证'}} />
<AStack.Screen name="Signup" component={Signup} options={{title:'我贴吧',
headerStyle: {backgroundColor: '#f4511e',},
headerTitleStyle: { alignSelf: 'center' },
headerTintColor: '#fff',
headerShown:true,
headerLeft:()=>null
}} />
<AStack.Screen name="Splash" component={SplashScreen} options={{headerShown:false}}/>
<AStack.Screen name="AppScreen" component={AppScreen} options={{headerShown:false}} />
<AStack.Screen name="Home" component={Home} options={{headerLeft:false}}/>
...
</AStack.Navigator>
</stateContext.Provider>
</authContext.Provider>
</propsContext.Provider>
However the splash screen won't move to Home after user signs up with valid local data and success:true. Here is the screen route:
App => Splash screen => Signup screen (2 screens here)=> Splash screen => Home Screen (didn't happen. Stuck at Splash screen)
The problem only happens recently and I am not aware of navigation being changed. What can causes react navigation holding on with splash screen and not move to Home screen?

How to reset stack when switching stack for authentication flow using react-navigation

I have a React Native project that uses react-navigation v6. This is the navigation structure:
const { user } = userContext;
<NavigationContainer>
{user === null ? (
<AuthStack.Navigator
initialRouteName={"SignIn"}
screenOptions={{ headerShown: false }}
>
<AuthStack.Screen name="SignIn" component={SigninScr} />
<AuthStack.Screen name="SignUp" component={SignupScr} />
<AuthStack.Screen
name="EmailVerification"
component={EmailVerificationScr}
/>
</AuthStack.Navigator>
) : (
<Tab.Navigator
initialRouteName={'HomeStack'}
screenOptions={{ headerShown: false}}
>
<Tab.Screen name={'HomeStack'} children={()=><HomeStack />}/>
<Tab.Screen name={'DiscoverStack'} children={()=><DiscoverStack />}/>
<Tab.Screen name={'CalendarStack'} children={()=><CalendarStack />}/>
<Tab.Screen name={'ProfileStack'} children={()=><ProfileStack />}/>
</Tab.Navigator>
)}
</NavigationContainer>
Essentially, there are two stacks:
Auth stack
Signin screen, signup screen, etc...
Regular stack
4 nested stacks (home stack, discover stack, calendar stack, profile stack)
I am using React Context to switch from the auth stack to the regular stack (or regular stack to auth stack)
The problem is that when the user logs off and signs back in, their stack was never reset and they are directed to the screen where they logged off. For example, user A logs in and goes to the profile screen, then they press log out. User A now logs back in, and instead of being sent to the home screen, they are sent back to the profile screen.
I want the navigation state of the regular stack to be reset when a user logs off. I have tried doing this, but it doesn't work (user still gets sent to the profile screen):
const { setUser } = this.context;
const { navigation } = this.props
navigation.reset({
index: 0,
routeNames: ['Home'],
routes: [{ name: 'Home' }],
});
setUser(null);
How can I completely reset the stack when switching stack for authentication flow?
For reference, this is what one of the stacks in the regular stack would look like:
const HomeStack = () => (
<Stack.Navigator screenOptions={{
headerTintColor: 'white',
headerTitleStyle: { color: 'white' },
headerStyle: { backgroundColor: colors.primary0 },
}}
>
<Stack.Screen name={'HomeScr'} component={HomeScr} />
...
</Stack.Navigator>
);
Actual behavior:
Expected behavior:

How to use modalPresentationStyle .fullscreen in React Native navigation

I am trying to create my first React Native application. I have a login screen from which I want to navigate to a register screen if users want to sign up.
To achieve this, I was thinking of opening a modal above the first screen (login). I created the following:
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
const Stack = createStackNavigator();
function RegisterScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>Register Screen</Text>
<Button onPress={() => navigation.goBack()} title="Go back" />
</View>
);
}
function MyStack() {
return (
<Stack.Navigator>
<Stack.Group>
<Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />
</Stack.Group>
<Stack.Group screenOptions={{ presentation: "modal", headerShown: false }} options={{modalPresentationStyle: 'fullScreen'}}>
<Stack.Screen name="Register" component={RegisterScreen} />
</Stack.Group>
</Stack.Navigator>
)
}
export default function App() {
return (
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}
This works perfectly fine, the modal shows. However, as you can see in this screenshot below, the modal is shown with modalPresentationStyle .automatic (in iOS). I want it to show as .fullScreen, so the hierarchy is not visible in the screen. Basically, I want the view to be shown from the safeArea/statusBar all the way down to the safeArea on the bottom.
How can I achieve this?
The terminology in React Native isn't the same as terminology in native apps. If you want a full-screen screen, you probably don't want a modal. If you want a vertical animation, change the animation based on docs:
screenOptions={{ cardStyleInterpolator: CardStyleInterpolators. forVerticalIOS, headerShown: false }}
https://reactnavigation.org/docs/stack-navigator/#animation-related-options
There's also no modalPresentationStyle: 'fullScreen' in documentation and Group component doesn't take an options prop.
The accepted answer states:
If you want a full-screen screen, you probably don't want a modal.
That's not necessarily true. Use
screenOptions={{ presentation: 'transparentModal' }}
or
screenOptions={{ presentation: 'fullScreenModal' }}
for a full screen modal animation you can't dismiss on iOS.

React native navigation 5 passing updated component

I am new to react native and its navigation modules. I have a simple dashboard.js file where I am using tab navigator like this -
<Tabs.Navigator tabBarOptions={{ activeTintColor: '#ff5757' }}>
<Tabs.Screen
options={{
tabBarIcon: ({ color }) =>
<Icon name='star-border' size={30} padding={15} color={color} />,}}
name={'Orders'}
component={Order}
initialParams={{user}}
/>
<Tabs.Screen
component= {AnotherComponent}
/>
As you can see I am passing InitialParams where I have user props. And I can easily get it in Order component by route.params.
However, in my dashboard component I also have a method that runs every 1 minute and updates user props.
I can't get the updated value of user props in Order component. I am stuck with this for 2 days. In the past I have done like this -
<Tabs.Screen
component = {() => <SomeComponent props= {props}/>}
And it worked fine. But with react-navigation 5 its not working any more.
Please help me if anyone knows. plz.
Thanks a lot.
The initial props seems to be a constant also as per the documentation you have to use redux or context api to update the badge counts in the tabs so I think it will be better to take that approach to handle this problem. Came up with a count changing scenario just like yours using context API.
const CountContext = React.createContext(0);
function HomeScreen() {
return (
<View>
<CountContext.Consumer>
{value => <Text>Home! {value}</Text>}
</CountContext.Consumer>
</View>
);
}
const MyTabs = () => {
const [count, setCount] = React.useState(0);
return (
<CountContext.Provider value={count}>
<View style={{ flex: 1 }}>
<Text>{count}</Text>
<Button title="count" onPress={() => setCount(count + 1)} />
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} options={{ title: 'My home' }} />
<Tab.Screen name="Settings" component={SettingsScreen} options={{ title: 'My home 2' }} />
</Tab.Navigator>
</View>
</CountContext.Provider>
);
};
This way you can skip the navigation params and directly send data to the tab, and this data can be read from other tabs or somewhere down the tree as well.
You can check the full snack here
https://snack.expo.io/#guruparan/5c2b97

React native: How can I have multiple drawer navigator links point to screens within the same stack navigator

I am new to react native and I haven't seen this question asked by anyone or haven't found a way around this.
Using react navigation 5 with expo.
Currently I have a the following app structure:
Stack navigator inside of drawer navigator.
Example of page structure:
Drawer Navigator ( links ):
Home (RouteStack)
Screen 1
Screen 2
Screen 3
RouteStack( screens) :
Home ( initial route )
Screen 1
Screen 2
Screen 4
How can I get Screen 1/Screen 2 link in drawer navigator load RouteStack: Screen 1/Screen 2?
These links are provided to easily jump to the required screen.
Need some guidance on how to achieve this.
I have thought of the possibility of drawer inside of stack, but there are screens inside of drawer that may not be listed in the stack. Hence, went with stack inside of drawer.
I have also tried to do a navigation.navigate(route.name) inside of RouteStack
Sample code:
Drawer navigator:
<NavigationContainer>
<Drawer.Navigator drawerContent={(props, navigation) => <CustomDrawerContent {...props} {...navigation} />}>
<Drawer.Screen name="Home" component={RouteStack} />
<Drawer.Screen name="MyItems" component={RouteStack} />
<Drawer.Screen name="ContactRep" component={RouteStack} />
<Drawer.Screen name="Settings" component={SettingInfo} />
</Drawer.Navigator>
</NavigationContainer>
Stack navigator (RouteStack) looks like this:
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ gestureEnabled: false, headerTitleAlign: 'auto' }}
// headerMode="float"
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: '',
headerStyle: {
backgroundColor: '#fff',
},
headerTintColor: '#000',
headerTitleStyle: {
fontWeight: 'bold'
},
headerLeft: props => <HeaderLeftMenu {...props} />,
headerRight: props => <HeaderRightMenu {...props} />,
headerTitle: props => <HeaderTitle {...props} />
}}
/>
<Stack.Screen
name="ContactRep"
component={ContactRep}
options={{ headerTitle: props => <HeaderTitle {...props} /> }}
/>
<Stack.Screen
name="MyItems"
component={MyItems}
options={{ headerTitle: (props, navigation) => <HeaderTitle {...props} /> }}
/>
</Stack.Navigator>
Thanks in advance and help is appreciated.
Your method is fine. But to clarify your ideas I will give you an example.
Assume I have a main Drawer. In that drawer I can navigate to 2 different screens. Inside those screens, I can navigate and do diferent things (like going to sub-screens), but never go outside the drawer.
To do this, we would have to created nested navigators. This meaning, one type of navigator if going to be inside another one. In our case of example:
<Papa Drawer>
<Screen 1 component={StackSon1}>
<Screen 2 component={StackSon2}>
<Papa Drawer>
And then StackSon1, for example, will look like this:
StackSon = () => {
return (
<Stack.Navigator>
<Stack.Screen>
<Stack.Screen>
...
)
}
React Navigation will also handle every drawer separately, meaning that you don't have to worry about the user creating an infinite chain of open screens.
Also, remember that, when we Nest navigators using a function (like I did) we must use return (or the simplified version of return with just parenthesis)
Hope it helps.