Reset stack after pressing TabBar route - react-native

I'm currently stuck with my project, I have a lot of nested navigators and I can't figure out how to reset one of them before navigating.
Here's my navigators structure : ( the Screen X is the same )
MainNavigator
TabBarNavigator
StackNavigator A
Screen A -> navigate to Screen X
Screen B
StackNavigator B
Screen C -> navigate to Screen X
Screen D
StackNavigator C
Screen E -> navigate to Screen X
Screen F
StackNavigator D
Other components
So when i'm navigating from Screen A to screen X, i can still navigate to other navigators ( B, C, D ) because the tabBar is still present and it's good.
However, if I open screen X in Navigator A, then navigate to a screen of Navigator B, when I come back on Navigator A I would like to land on Screen A and not on Screen X as it does right now ( the Screen X is still on top of Navigator A's stack ).
To resume, my nav actualy does :
- Navigator A -> Screen A -> Screen X -> Navigator B -> Screen B -> Go Back to Navigator A but lands on Screen X
And i would like it to do :
- Navigator A -> Screen A -> Screen X -> Navigator B -> Screen B -> Go back to Navigator A and land on Screen A
I tried to set this up in my Screen X navigation option but it does only work on Navigator A :
tabBarOnPress: () => {
navigation.goBack(navigation.state.key)
},
Any help would be appreciated since i've been stuck on this for a while now.
React : 16.0.0
React Native : https://github.com/expo/react-native/archive/sdk-23.0.0.tar.gz
React navigation : ^1.0.0-beta.19
Currently working on iOS simulator

With redux integration you can use the reset method of NavigationActions:
https://reactnavigation.org/docs/navigators/navigation-actions
On the reset method example you'll find:
import { NavigationActions } from 'react-navigation'
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Profile'})
]
})
this.props.navigation.dispatch(resetAction)

In react-navigation nesting of tab is bit complex I also faced something similar to this
NavigationActions.reset({
index: 0,
key: null,
actions: [
NavigationActions.navigate({routeName: 'routeNameToNavigate'})
]
});
giving key value solved my problem and navigated me root from nested. Hope this will solve your problem. Here is issue dicussed
https://github.com/react-community/react-navigation/issues/1949

Related

clear stack when navigating to nested stack navigator inside bottom tab navigator

Current Behavior
My react-native application consists of a BottomTabNavigator that contains several StackNavigators. A simplified example of my structure looks like this
userLoggedIn or signinSkiped ? (
BottomTab
Tab 1
Stack
Screen 1
Screen 2
Tab 2
Stack
Screen 1
Screen 2
) : ( Stack
SigninScreen
RegisterScreen
)
**My problem is: **
I log in into my application
I am on Screen 1 of the Tab 1.
From the Screen 1 of the Tab 1 i navigate to Screen 2 of the Tab 1 on the press button.
From the Screen 2 of the Tab 1 i navigate to Screen 2 of the Tab 2 on the press button.
I log out from my application
I am on SigninScreen
I click on the button "signinSkip" on the SigninScreen (signinSkiped = true)
I am on the Screen 1 of the Tab 1
I click on Tab 2
Screen 2 of the Tab 2 is displayed
**Expected behavior: **
When I click on Tab 2 as described in the step 9 above, Screen 1 of the Tab 2 should be displayed and not the Screen 2.
It works as expected, if I do following steps:
I sign in into my application
I am on the Screen 1 of the Tab 1
I click on Tab 2 and I'm on the Screen 1 of the Tab 2
From the Screen 1 of the Tab 2 i navigate to Screen 2 of the Tab 2 on the press button.
I log out from my application
I am on SigninScreen
I click on the button "signinSkip" on the SigninScreen (signinSkiped = true)
I am on the Screen 1 of the Tab 1
I click on Tab 2
Screen 1 of the Tab 2 is displayed
I assume, it has to do with refreshing of stack after logging out, but I'm not sure.
i would really appreciate your help
I tried following:
Navigate from Screen 2 to Screen 1 of the Tab 2 if the user loggs out (within the onAuthStateChanged listener). I get the expected result, but it leads to the error: Can't perform a React state update on an unmounted component
you can reset your navigation stack when the user logs out of your application. Doing this will keep the behavior consistent.
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{
name: 'SigninScreen',
}
],
})
);
To answer your question on why the SigninScreen. You have nested navigators, which means that whatever you are doing in the parent navigator (tab navigator) is not going to affect the child navigator (screen 1 and 2). The reason why you are seeing the behavior described is that the mounted screens don't get unmounted. Whatever you had in your child navigator won't be reset when the user navigate away from it (i.e. clicking Tab 1 or tab 3 etc.)
The code above will reset all of that when the user gets to the login screen. This will remove all the mounted screens, which will make sure when the user click on Tab 2, screen 1 always gets mounted first.
Alternately, you can add a tab press listener to manually goto Screen 1 when the user press Tab 2.
<Tab.Screen name="Tab 2" component={Tab2}
listeners={({ navigation }) => ({
tabPress: (event) => {
e.preventDefault();
navigation.navigate(“Tab2”, {screen: “Screen1” };
}
})}
/>

How to goBack globally between stacks in React Navigation?

I am using react navigation ("#react-navigation/native": "^5.1.3") and I have the following setup:
BottomNavigation
-stack1
-stack2
It looks like goBack() is local to the stack. What that means is that if I navigate from a page in stack1 to a page in stack2, I am unable to go the the page I came up from.
Solutions (or rather hacks) that didn't work for me:
pass the source screen as param and then navigate. That isn't a real back button and does not play well with android back button.
Put all pages in bottom navigation. Bottom navigation does not have animations it seems, so I can not achieve the right transitions
Put all pages in stack navigation. In this case I lose the fixed bottom navigation. I can add it to each page, but when transitioning it will go away with the old screen and come again with the new one, which is undesirable.
So I am wondering if I am missing something big here, like a globalBack() that I overlooked?!
And also, I am looking for a solution to this problem which remains.
Naturally if you have bottoms tabs with each tab having its own stack navigator, calling navigation.goBack() will go back from one screen inside stack navigator to previous screen inside that same stack navigator. That's how navigation works in pretty much every app. Pressing back button or swiping back does not change tab for you, tabs are more like separate small apps by itself. If you want to specifically jump from one tab to another instead of going back in stack, use navigation.dispatch(TabActions.jumpTo('Profile')). If pressing something inside tab#1 makes you go to to tab#2 then this screen most likely also belongs to tab#1
also, take a look at backBehavior prop of Tab.Navigator, it might be doing what you want depending on what exactly it is you want https://reactnavigation.org/docs/bottom-tab-navigator/#backbehavior
I'm using bottom tab navigator with 2 stacks as well. I faced similar issue and agree with #Max explanation. Due to my Notification screen is in Stack 1, I have to goBack to Notification after navigating away to Detail screen. After searching for the fix, I'm using this workaround (for v6).
Tab 1 - Stack 1 (Home > Notification screen)
Tab 2 - Stack 2 (Reward Home > Reward Detail screen)
I passed a param when navigating from Notification to RewardDetail. Then I override the headerLeft and use BackHandler to handle Android back function.
Notification.js
navigation.navigate('RewardStack', {
screen: 'RewardDetail',
initial: false,
params:{notification: notification_data_source}
})
RewardDetail.js
const payload = route.params.notification
//1. override headerLeft button
useLayoutEffect(() => {
if(payload)
navigation.setOptions({
headerLeft: () => (
<Button
TouchableComponent={TouchableOpacity}
buttonStyle={{paddingTop:4, paddingLeft:0}}
type='clear'
icon={<Icon name={'chevron-left'} size={30} style={{color:'#FFF'}} />}
onPress={()=>{
navigation.goBack()
navigation.navigate('Notification') //can use this only
}}
/>
)
})
}, [navigation]);
//2. Add BackHandler
useEffect(() => {
const onBackPress = () => {
if (payload) {
navigation.goBack()
navigation.navigate('Notification') //can use this only
return true
} else {
return false
}
}
BackHandler.addEventListener('hardwareBackPress', onBackPress)
return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress)
}, [navigation]);
I can just use navigation.navigate('Notification') to return to Notification but this will cause Detail screen to stay mounted in Stack 2. I want the Stack 2 to return to RewardHome after go back to Notification. Hence I used:
navigation.goBack() //pop screen to RewardHome
navigation.navigate('Notification') //jump to Notification

Why Navigation.goBack() not working properly?

I am using following way to create navigation system
StackNavigator -> DrawerNavigator -> (Screen A, Screen B, Screen C)
Screen A is initial Route
Screen A to Screen B Using
this.props.navigation.navigate("Screen B") //Working Fine
Screen B to Screen C Using
this.props.navigation.navigate("Screen C") //Working Fine
In Screen C
this.props.navigation.goBack() //Not Working
But
this.props.navigation.goBack(null) //It's going to Screen A instead of Screen B
What's wrong here.
Please help me Thank you.
As you didn't show the navigation structure of the drawer, I don't know how the 3 screens are put inside of it. I'm assuming they are 3 different drawerScreens
This happens because you are using a DrawerNavigation, that doesn't create a history of screens when you navigate around it.
To solve this you have to change the navigation structure to something like:
DrawerNavigation => StackNavigator => Screen A, B, C
You can specify backBehavior="history" inside Drawer.Navigator and it shouldn't move you to the initial root on goBack anymore :)
Example:
<Drawer.Navigator
backBehavior="history"
>
...
As the answer above is, the drawer navigators are not in the stack, so you can't tell the path of your journey.
the key property for goBack() is a dynamically created string, created by react-navigation whenever navigate to a new route.
These stack keys are stored in this.props.navigation.state
NOTE: Use .goBack(null) if your goal is to return to any place
without specifying a closing target.
Like this example, you can add to the stack.
Example
const Drawers = createDrawerNavigator(
{
A: {
screen: HomeScreen
},
...
},
{
initialRouteName: "A"
}
);
const RootStack = createStackNavigator(
{
Drawers: {
screen: Drawers
},
otherStack: {
screen: otherStack
},
....

Cannot properly navigate between two different stacks in react native and keep back functionallity

Currently these are my screens in my react native app.
Root Nav - (SwitchNavigator)
Stack A - (BottomTabNavigator)
Page A
Page B
Stack B - (StackNavigator)
Page C
Page D
I am trying to navigate to page C/D From pages A/B But when I try to navigate using this.props.navigation.navigate() It will navigate correctly, but the history functionality such as swiping right or calling goBack() to go to the previous page (in a different stack) does not work.
When navigating to page D and swiping right, it goes to page C and swiping right again does not do anything.
Different stacks are meant to stand on their own, so if what you need is to keep the navigation history between those screens, you have to set them up in the same stack. Stacks can be set up in your flow just like screens, for example, setting up a stack navigator inside a drawer navigator:
/**
* User drawer stack
*/
const DrawerStack = DrawerNavigator({
Home: {screen: HomeStack}, //HomeStack is a StackNavigator
}, {
contentComponent: DrawerContainer,
initialRouteName: 'Home',
});
With this rethink what you want your history like. If I understood your use case correctly, you want A/B to share history with C/D, I'd say you need your stack to be like:
Root Nav - (SwitchNavigator)
Stack B - (StackNavigator)
Stack A - (BottomTabNavigator)
Page A
Page B
Page C
Page D
If you can't do that for some reason, then you will need to capture back presses and swipes manually to do the behavior yourself.

React navigation weird back button and pop behavior

I have a nested navigator in my react native App
cost Main = createTabNavigator({
Home:Home,
Challenge:Challenge,
Products:Products,
Options:Options
})
const Options = createStackNavigator({
OptionsScree:OptionsScreen,
Details:Details,
Profile:Profile
})
I can navigate from Home screen to Details by simply doing this.props.navigationnavigate('Details')
but when I'm doing this.props.navigation.pop()
it is supposed to take me to last focused screen which was Home screen but it takes me to OptionsScreen
is there a way to go back to Home ?
Try moving Main tab navigator component into stack navigator as below.
const Options = createStackNavigator({
Main:Main,
OptionsScree:OptionsScreen,
Details:Details,
Profile:Profile
})
As Home screen is not present in stack, this.props.navigation.pop() can not pop that screen for you. It pops previous screen in the stack, if none pops the first screen which is in your case is OptionsScreen.