React navigation set initial route to another stack screen - react-native

I have a react native app using react navigation. My app has 3 different stacks = { ROOT, AUTH, USER }.
Stacks ROOT & AUTH are managed by authentication flow, if there's a token I switch to ROOT otherwise AUTH. That works fine. In my USER stack, is where I place "universal" screens (screens that can be accessed either from root or auth stack). Let's consider one of my USER stack screen is ValidateUserAccount (which is accessed through a link from the email). The problem comes when for example I open my app and I'm in the LoginScreen, in the AUTH stack. On iOS, the go back has the previous screen title. Since the previous screen it's in another stack , it shows "< auth", instead of "< login". Same happens with the ROOT. If I'm at HomeScreen, in the ROOT stack and I open the ValidateUserAccount, the go back button is "< root".
<MainStack.Navigator
screenOptions={{
headerShown: false
}}>
{accessToken ? (
<MainStack.Screen
name="root"
component={BottomTabNavigator}
/>
) : (
<MainStack.Screen
name="auth"
component={AuthenticationStack}
/>
)}
<MainStack.Screen
name="user"
component={UserStack}></RootStack.Screen>
</MainStack.Navigator>
How can I manage to display the go back with the previous screen title instead of previous stack title, eventhough it's in another stack?
Is it possible? or the only solution is to hide the go back title?

Related

How can I navigate from login screen to a bottomtab screen?

How can I navigate to a bottomtab screen rather than a stack screen? The goal is to take the user to the main home page onPress of the sign in button. I initially created a Stack.Screen and added the homescreen component but that crashed the header and the bottom tab navigation and there was also the back button in the header which isn't supposed to be because the home screen is the main screen. Is there a way to navigate to the bottom tab screen from the sign in component? I'm a beginner by the way and also not so good at using stack overflow
if you're using react router than this may possible with useNavigate() and Link. Also you can add custom javascript window.location.href ="/pagename"
Usage of useNavigate() before return of function-
const navigate = useNavigate()
onClick = (e)=>(
e.preventDefault()
navigate('/home')
)
Usage of Link inside body-
<Link to="/home"></Link>
Usage of custom javascript inside body-
<button onClick = (()=>window.location.href="/home"))>Click me</button>
Hope you'll like the answer. But if you still face any issue just lemme know.
I suggest you to try an Authentication flow approch written by 'React-Navigator' API.
The main idea of that is using 2 Navigators.
Stack Navigator for 'Login'
Tab Navigator for pages which logged in users can see
However, to make this flow available, you need to add Global State Management library like Redux / React Context to handle which navigator is showing. Once the state is set, the app will auto select the navigator used. You don't need to call any function for navigation.
<NavigationContainer>
<Stack.Navigator>
{
!redux.isLoggedIn ?
<Stack.Group>
<Stack.Screen
name="auth"
component={Auth}
/>
</Stack.Group>
:
<Stack.Group>
<Stack.Screen
name="home"
component={YourHomeTabNavigator}
/>
</Stack.Group>
}
</Stack.Navigator>
</NavigationContainer>

react-native-navigation: set screen as root parent

I'm using react-native-navigation with:
a custom animated app loading screen
my home screen
I created a Stack.Navigator as follows:
<Stack.Navigator
initialRouteName="AnimatedAppLoader"
>
<Stack.Screen
name="AnimatedAppLoader"
component={AnimatedAppLoader}
/>
<Stack.Screen
name="Home"
component={Home}
/>
</Stack.Navigator>
My AnimatedAppLoader waits that the app is ready then navigate to the Home screen through:
navigation.navigate('Home');
The problem is that the Home screen becomes a child of AnimatedAppLoader screen and users can go back to the loader screen.
I tried to disable back button and back gestures but this solution does not seem proper since android users can still go back with the system back button.
Is there a proper way to set my Home screen as the root parent of my app?
use navigation.replace('Home'); replace will replace the current screen with a new one rather than adding a new screen
you can read more at the props
https://reactnavigation.org/docs/navigation-prop/

Navigate from inner navigator to outer navigator generate extra screen slide

I have a problem during the logout in my react native app. I set many navigators to handle multiple navigation flow, but when I try to logout from the app, the login screen appears two times.
I try to explain how I organize my navigators below:
I created a TabNavigator which handle the main navigation of the app if a user is logged in otherwise I show the LoginNavigator which handle login, registration and password forgot screens.
I use a state, stored on redux for handling the login state (isLoggedIn).
<NavigationContainer>
{isLoggedIn ? <TabNavigator/> : <LoginNavigator/>}
</NavigationContainer>
Into the TabNavigator I set other navigator for handling page flow in each sections, like the exemple below:
TabNavigator
Screen X
Navigator1
Screen A
Screen B
Navigator2
Screen C
Screen D
Screen Y
Into the Screen C I'd like to logout from the app, so I call an action which set the isLoggedIn state to false.
What happens is that the Login screen (the inital screen of LoginNavigator) appears, but it suddently slides off and another Login screen appears.
It happens only from nested screen, instead if I try to logout from Screen X or Screen Y it works perfectly fine.
Does anyone encounter this problem? How can I solve this behaviour?
I solved this behaviour!
Instead of showing the correct navigator using a ternary operation, base on redux state, I wrap TabNavigator and LoginNavigator inside a custom stack navigator with a WaitingScreen.
I set the WaitingScreen as inital route and I moved the logic about which route between MainNavigator and LoginNavigator has to be shown inside WaitingScreen, in a useLayouEffect with isLoggedIn as dependecy.
<NavigationContainer>
<Stack.Navigator
initialRouteName={NavConst.LOADING}
screenOptions={{
headerShown: false,
contentStyle: {
backgroundColor: Color.primary600,
},
animation: "none",
}}
>
<Stack.Screen name={NavConst.LOADING} component={WaitingScreen} />
<Stack.Screen name={NavConst.LOGIN_NAV} component={LoginNavigator} />
<Stack.Screen name={NavConst.MAIN_NAV} component={MainNavigator} />
</Stack.Navigator>
</NavigationContainer>
and inside the WaitingScreen:
useLayoutEffect(() => {
isLoggedIn
? navigation.navigate(NavConst.MAIN_NAV);
: navigation.navigate(NavConst.LOGIN_NAV);
}, [isLoggedIn]);

Unable to go back after refreshing from a Modal screen using React Navigation

Let's suppose I have a TabNavigator. In a screen, I'm able to navigate to a modal screen (full screen modal => it's placed outside the TabNavigator stack) and go back but, if I refresh the browser in the modal screen (F5), I'm unable to go back. The go back button disappears.
I can even reproduce it with the Expo init typescript tabbed default project.
Video describing the problem: https://recordit.co/4PULNdWRPT
Code: https://github.com/MADSENSE/Madsense.ReactNative.Sample/tree/master
Does anywone knows how to fix this / any workaround?
This is what you expect while navigating a web app. Whoever, you can force the icon to show and navigate to wherever you want manually.
example:
<Stack.Screen
name="..."
component={...}
options={navigation => ({
headerLeft: props => <IconComponent onPress={navigation.navigate("...")} />,
})}
/>
Also, you have to navigate to a screen by its name navigation.navigate("...") because you can't tell from where the user went to your screen.

Navigating from a nested screen to another nested screen in a different Tab Stack (react-navigation)

I'm using react navigation 5 (with react native) and my navigation set up looks like this:
// Root
<NavigationContainer>
<RootStack.Navigator mode="modal" headerMode="none">
<RootStack.Screen name="Auth" component={AuthStackNavigator} />
<RootStack.Screen name="App" component={BottomTabsNavigator} />
</RootStack.Navigator>
</NavigationContainer>
// App
<Tab.Navigator tabBar={bottomTabBar}>
<Tab.Screen name="ScreenA1" component={StackA} />
<Tab.Screen name="ScreenB1" component={StackB} />
</Tab.Navigator>
// TAB A
<StackA.Navigator headerMode="none">
<StackA.Screen name="ScreenA1" component={ScreenA1} />
<StackA.Screen name="ScreenA2" component={ScreenA2} />
</StackA.Navigator>
// TAB B
<StackB.Navigator headerMode="none">
<StackB.Screen name="ScreenB1" component={ScreenB2} />
<StackB.Screen name="ScreenB2" component={ScreenB2} />
</StackB.Navigator>
So inside my App i have 2 Bottom Tabs (Tab A and Tab B) each having 2 nested screens (Screen A1>A2 and B1>B2).
So when i tap on Tab A i go to ScreenA1 then in there i can move on to ScreenA2. Same for Tab B.
Now on ScreenB2 from Tab B i have a button that should navigate the user to Screen A2 with some data to prefill on that screen.
If i do it like this:
navigation.navigate('ScreenA1', {
screen: 'ScreenA2',
params: { data },
});
I'll land on ScreenA2 with the data, but:
If i visited ScreenA2 before, the previous state persists and i can see its old state and data.
If i never visited ScreenA2 before it's now not inside the Tab A Stack, but instead pushed on top of ScreenB2.
So i guess i would need to reset the screen before i navigate to it (or unmount whenever i leave it) and also make sure that it gets put inside the Tab A Stack on creation, so when i try to call goBack from Screen A2 i land on Screen A1. Maybe navigate back to root first and call the screen from there without the user seeing all screens flashing up.
You can replace
navigation.navigate('ScreenA1'...
By
navigate.push('ScreenA1'...
That way, a new route will be added to your navigation stack, with new state and props.
Resolved it with this:
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{
name: 'ScreenA1',
state: {
routes: [
{
name: 'ScreenA1',
},
{
name: 'ScreenA2',
params: { data },
},
],
},
},
],
}),
);
Notice how i have 'ScreenA1' twice in there. I guess that's necessary because the Navigator and the first Screen inside the Navigator share the same route name