Resetting screen to first Parent screen, from a nested screen (React navigation & React Native)

Viewed 860

I've followed the documentation for creating bottom tab navigation with react-navigation v5 ("@react-navigation/native": "^5.2.3")

Currently is partially used this example in my project from docs https://reactnavigation.org/docs/bottom-tab-navigator/ to fit the needs of version 5.

Example might be following

// Navigation.tsx

import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import { TabActions } from '@react-navigation/native';
import * as React from 'react';

function Navigation({ state, descriptors, navigation }: BottomTabBarProps) {

  return (
    <View>
      {state.routes.map((route, index) => {
        const { options } = descriptors[route.key];
        const isFocused = state.index === index;
        const onPress = () => {
          const event = navigation.emit({
            type: 'tabPress',
            target: route.key,
            canPreventDefault: true,
          });

          if (!isFocused && !event.defaultPrevented) {
            const jumpToAction = TabActions.jumpTo(options.title || 'Home');
            navigation.dispatch(jumpToAction);
          }
        };

        return (
          <TouchableOpacity
            key={options.title}
            accessibilityLabel={options.tabBarAccessibilityLabel}
            accessibilityRole="button"
            active={isFocused}
            activeOpacity={1}
            testID={options.tabBarTestID}
            onPress={onPress}
          >
            {route.name}
          </TouchableOpacity>
        );
      })}
    </View>
  );
}

export default Navigation;

However, I have a couple of nested StackNavigators as described in AppNavigator.tsx

AppNavigator.tsx

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import React from 'react';
import { AppState, AppStateStatus } from 'react-native';

import Navigation from '../components/navigation/Navigation';
import AccountScreen from '../screens/account';
import SettingsScreen from '../screens/settings';
import SupportScreen from '../screens/support';

import HomeNavigator from './HomeNavigator';
import TransactionNavigator from './TransactionNavigator';

const { Navigator, Screen } = createBottomTabNavigator();

const AppNavigator = () => {

  return (
    <View>
      <Navigator tabBar={(props) => <Navigation {...props} />}>
        <Screen
          component={HomeNavigator}
          name="Home"
          options={{ title: 'Home' }}
        />
        <Screen
          component={TransactionNavigator}
          name="Transactions"
          options={{
            title: 'Transactions' }}
        />
        <Screen
          component={AccountScreen}
          name="Account"
          options={{ title: 'Account' }}
        />
        <Screen
          component={SupportScreen}
          name="Support"
          options={{ title: 'Support' }}
        />
        <Screen
          component={SettingsScreen}
          name="Settings"
          options={{
            title: 'Settings' }}
        />
      </Navigator>
    </View>
  );
};

export default AppNavigator;

And I am aiming for resetting the nested StackNavigator each time user leaves it. So example can be HOME -> TRANSACTIONS -> TRANSACTION_DETAIL (which is part of a nested navigator) -> HOME -> TRANSACTIONS

currently, I see a TRANSACTION_DETAIL after the last step of the "walk through" path. Nevertheless, I want to see TRANSACTIONS instead. I found that if I change

if (!isFocused && !event.defaultPrevented) {
  const jumpToAction = TabActions.jumpTo(options.title || 'Home');
  navigation.dispatch(jumpToAction);
}

to

if (!isFocused && !event.defaultPrevented) {
  navigation.reset({ index, routes: [{ name: route.name }] });
}

it more or less does the thing. But it resets the navigation, so it is unmounted and on return back, all data are lost and need to refetch.

In navigation is PopToTop() function that is not available in this scope.

Also I tried to access all nested navigators through descriptors, yet I have not found how to correctly force them to popToTop.

And the idea is do it on one place so it will be handled automatically and there would not be any need to implement it on each screen.

1 Answers

I have tried with navigator.popToTop() but it was not working. It may be stackNavigator and TabNavigator having a different history with the routes. I have fixed the issue with the below code. "Home" is my stack navigator name and another "Home" is screen name (Both are same for me)

tabBarButton: props => (
        <TouchableOpacity
          {...props}
          onPress={props => {
            navigation.navigate('Home', {
              screen: 'Home'
            })
          }}
        />
      ),
Related