DEV Community

Spencer Carli
Spencer Carli

Posted on • Originally published at reactnativeschool.com

React Navigation v5: Reset Stack Inside Tab After Leaving Tab

Originally published on reactnativeschool.com

Problem: You have a stack navigator inside a tab and, when going to a different tab, you want to reset the stack navigator inside the tab you just left.

Example

import * as React from 'react';
import { View, Text, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { CommonActions, StackActions } from '@react-navigation/native';

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Home Screen</Text>
      <Button title="Details" onPress={() => navigation.push('Details')} />
    </View>
  );
}

function DetailsScreen() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Details Screen</Text>
    </View>
  );
}

function SettingsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Settings Screen</Text>
      <Button
        title="Settings Details"
        onPress={() => navigation.push('SettingsDetail')}
      />
    </View>
  );
}

function SettingsDetailScreen() {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Settings Details Screen</Text>
    </View>
  );
}

const Stack = createStackNavigator();
const Stack2 = createStackNavigator();
const Tab = createBottomTabNavigator();

const HomeStack = () => (
  <Stack.Navigator>
    <Stack.Screen name="Home" component={HomeScreen} />
    <Stack.Screen name="Details" component={DetailsScreen} />
  </Stack.Navigator>
);

const SettingsStack = () => (
  <Stack2.Navigator>
    <Stack2.Screen name="Settings" component={SettingsScreen} />
    <Stack2.Screen name="SettingsDetail" component={SettingsDetailScreen} />
  </Stack2.Navigator>
);

function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="HomeTab" component={HomeStack} />
        <Tab.Screen name="SettingsTab" component={SettingsStack} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

For this example app I only want to reset the home stack if I leave that tab. If I'm in a nested screen on settings I want to leave it as is.

https://media.giphy.com/media/FcMdPWSY547cAPhStD/giphy.gif

Solution

This isn't a great solution (notice the "dangerouslyGetState") but it seems to work well enough. This solution is built on top of the solution provided in this Github issue.

// ...

// https://github.com/react-navigation/react-navigation/issues/8583
const TAB_TO_RESET = 'HomeTab';
const resetHomeStackOnTabPress = ({ navigation, route }) => ({
  tabPress: (e) => {
    const state = navigation.dangerouslyGetState();

    if (state) {
      // Grab all the tabs that are NOT the one we just pressed
      const nonTargetTabs = state.routes.filter((r) => r.key !== e.target);

      nonTargetTabs.forEach((tab) => {
        // Find the tab we want to reset and grab the key of the nested stack
        const tabName = tab?.name;
        const stackKey = tab?.state?.key;

        if (stackKey && tabName === TAB_TO_RESET) {
          // Pass the stack key that we want to reset and use popToTop to reset it
          navigation.dispatch({
            ...StackActions.popToTop(),
            target: stackKey,
          });
        }
      });
    }
  },
});

function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen
          name="HomeTab"
          component={HomeStack}
          // Note that resetHomeStackOnTabPress should be added to each tab
          listeners={resetHomeStackOnTabPress}
        />
        <Tab.Screen
          name="SettingsTab"
          component={SettingsStack}
          listeners={resetHomeStackOnTabPress}
        />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

https://media.giphy.com/media/S4A8Vj7sjIvazucZ0r/giphy.gif

If you want every stack to reset when changing tabs you can remove the tabName === TAB_TO_RESET check.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more