17

I have the following route structure:

StackNavigator
-StackNavigator
-TabNavigator
--Tab1
---Route 1 (Stack) (initial)
---Route 2 (Stack)

--Tab2
---Route 3 (Stack) (initial)
---Route 4 (Stack)

When I visit Tab1 -> Route 1 -> Route 2 -> Tab2 and go back to Tab1, the active route is 2 instead of the initialRoute 1.

I'm doing the following:

tabBarOnPress: ({ scene }) => {
    const { route } = scene;
    const tabRoute = route.routeName;
    const { routeName } = route.routes[0];

    navigation.dispatch(NavigationActions.navigate({ routeName: tabRoute }));

    navigation.dispatch(NavigationActions.reset({
        index: 0,
        actions: [
            NavigationActions.navigate({ routeName }),
        ],
    }));
},

but the problem is that it first shows Route 2 and then navigate to Route 1.

How can I reset the previous tab/screens, so when I switch the tab always to show directly the initial route.

Hristo Eftimov
  • 13,845
  • 13
  • 50
  • 77
  • I'm busy atm, thus making only a comment. But google for `jumpToIndex`, it's a prop of TabBar which can also be used for reseting the stack. – Samuli Hakoniemi Jan 29 '18 at 16:06
  • You can check out my answer to a very similar question here: https://stackoverflow.com/a/48446647/2805067 – Tal Z Feb 01 '18 at 13:15
  • Does this answer your question? [React Native Navigation: Reset Stack Navigator](https://stackoverflow.com/questions/65445398/react-native-navigation-reset-stack-navigator) – Kishan Bharda Feb 08 '21 at 04:36

3 Answers3

17

Solution for version 5.x.x and version 6.x.x:

Pass a listener to the screen component:

<Tab.Screen
     name="homeTab"
     component={HomeStackScreen}
     listeners={tabBarListeners}
/>

Then on this listener, navigate the user every time when he presses the tab:

const tabBarListeners = ({ navigation, route }) => ({
    tabPress: () => navigation.navigate(route.name),
});

Credits: https://github.com/react-navigation/react-navigation/issues/8583

Solution for version 4.x.x:

tabBarOnPress: ({ navigation }) => {
  navigation.popToTop();
  navigation.navigate(navigation.state.routeName);
}

Credits: https://github.com/react-navigation/react-navigation/issues/1557

Solution for versions 2.x.x and 3.x.x:

The problem is that when I reset the route, I need to pass the navigation action of the previous routeName (leaving tab) and to dispatch a new navigation action for the next route:

tabBarOnPress: ({ previousScene, scene }) => {
    const tabRoute = scene.route.routeName;
    const prevRouteName = previousScene.routes[0].routeName;

    navigation.dispatch(NavigationActions.reset({
        index: 0,
        actions: [
            NavigationActions.navigate({
                routeName: prevRouteName
            }),
        ],
    }));

    navigation.dispatch(NavigationActions.navigate({
        routeName: tabRoute
    }));
}
Hristo Eftimov
  • 13,845
  • 13
  • 50
  • 77
7

use unmountOnBlur option it works for all types of navigators , stack navigator , drawer navigator , bottomtab navigator

<Tab.Screen name="Home" component={DrawerNavigator} options={{unmountOnBlur:true}}/>

pass unmountOnBlur in the options prop of the screen of the navigator

KUMAR NEERAJ
  • 71
  • 1
  • 1
  • Worked really well for me. Why there are no upvotes? Are there drawbacks to this solution? – Sergey Yarotskiy Jun 24 '21 at 21:20
  • @SergeyYarotskiy There is a comment,`Normally, we don't recommend enabling this prop as users don't expect their navigation history to be lost when switching tabs. If you enable this prop, please consider if this will actually provide a better experience for the user.` at official page(https://stackoverflow.com/questions/61611483/how-to-set-header-options-for-react-navigation-v5) – Minkyu Kim Dec 23 '21 at 06:39
  • But this would be a good answer, simple and easy. – Minkyu Kim Dec 23 '21 at 06:40
  • I tried this and it causes flickering of the tab when switching tabs. And also it breaks the stack if you navigated to a nested screen from another stack. Then with this option enabled the stack always starts on the nested screen when changing tabs. So indeed there are serious drawbacks unfortunately. – Episodex Mar 24 '22 at 07:01
  • @Episodex : I also found the flickering effect when switching between the tabs, if we give unmountonBlur:true which is very annoying . But at the same time , i need to re-render each tab when i press tabicon each time. Do you have any solution for this? – Rotomac17 Jul 18 '22 at 07:36
0

You can give a try with reset props like this :

tabBarOnPress: ({ scene }) => {
    const { route } = scene;
    const tabRoute = route.routeName;
    const { routeName } = route.routes[0];

    navigation.dispatch(NavigationActions.reset({
        index: 1,
        actions: [
            NavigationActions.navigate({ routeName }),
            NavigationActions.navigate({ routeName: tabRoute })
        ],
    }));
},

Edit : If this doesn't solve the issue you can check this github issue with some workarounds

Dyo
  • 4,429
  • 1
  • 15
  • 30
  • Unfortunately, it doesn't work. It threw an error: `There is no route defined for key Tab2. Must be one of: 'Route 1', 'Route 2'`. It appears if I directly click on the second tab. – Hristo Eftimov Jan 29 '18 at 17:06
  • It was a while ago, but I think this worked: https://stackoverflow.com/a/68788917/219547 . I commented that something was wrong there but I see in the code it works like this currently. One change is `dangerouslyGetState` to just `getState()`. It was also important to not use `NativeStackNavigator` but `StackNavigator` to avoid flickering. – Episodex Jul 26 '22 at 07:03