Update screen title to that of selected tab navigation

Viewed 1069

I am in the process of implementing drawer navigation with nested tab navigation within my app.

At present I have two issues that I cannot work out so far and am looking for pointers. I am using React Navigation v6.

  1. Upon clicking any of my tab navigator links I notice that my screen title is always set to "Home". Can this be updated to the current selected tab?

  2. The last clicked tab appears to keep its state when using the drawer links, the journey would look like

  • Start on home page (Renders home screen fine)
  • click userprofile tab (Renders user profile page fine)
  • then click "Book New Class" from within the Drawer, (Renders New Class page fine)
  • then click "Home" from within the Drawer (This renders the user profile screen)

I have created a snack that will hopefully show the issues I'm facing https://snack.expo.dev/@richlewis14/drawer-and-tab-navigation

DrawerNavigator.js

import React, {useContext} from 'react';
import CustomDrawer from '../components/CustomDrawer.js';
import {BookNewEvent} from '../screens/events/BookNewEvent.js';
import {UserProfile} from '../screens/profile/UserProfile.js';

import BottomTabNavigator from '../navigation/BottomTabNavigator.js';
import {createDrawerNavigator} from '@react-navigation/drawer';
import Ionicons from 'react-native-vector-icons/Ionicons';

const Drawer = createDrawerNavigator();

const DrawerNavigator = ({navigation}) => {
  return (
    <Drawer.Navigator
      drawerContent={props => <CustomDrawer {...props} />}
      screenOptions={{
        drawerActiveBackgroundColor: '#2B6EB5',
        drawerActiveTintColor: '#fff',
        drawerInactiveTintColor: '#333',
        drawerLabelStyle: {marginLeft: -25, fontSize: 15},
      }}>
      <Drawer.Screen
        name="Home"
        component={BottomTabNavigator}
        options={{
          title: 'Home',
          drawerIcon: ({color}) => <Ionicons name="home" size={22} color={color} />,
        }}
      />
      <Drawer.Screen
        name="BookNewEvent"
        component={BookNewEvent}
        options={{
          title: 'Book Class',
          drawerIcon: ({color}) => <Ionicons name="calendar-outline" size={22} color={color} />,
      }}
    />
    </Drawer.Navigator>
  );
};
export default DrawerNavigator;

BottomTabNavigator.js

import React, {useContext} from 'react';

import {UserLandingPage} from '../screens/landing/UserLandingPage.js';
import {BookNewEvent} from '../screens/events/BookNewEvent.js';
import {UserProfile} from '../screens/profile/UserProfile.js';


import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import Ionicons from 'react-native-vector-icons/Ionicons';

const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();

const UserHomeStack = () => {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={UserLandingPage}
        options={{headerShown: false}}
      />
    </Stack.Navigator>
  );
};


const BottomTabNavigator = ({navigation}) => {
  return (
    <Tab.Navigator
      screenOptions={{
      headerShown: false,
      tabBarShowLabel: false,
    }}>
      <Tab.Screen
        name="Home2"
        component={UserHomeStack}
        options={{
          tabBarIcon: () => <Ionicons name="home" size={22} />,
        }}
      />
      <Tab.Screen
        name="UserBookNewEvent"
        component={BookNewEvent}
        options={{
          tabBarIcon: () => <Ionicons name="add-circle" size={22} />,
        }}
      />
      <Tab.Screen
        name="UserProfilePage"
        component={UserProfile}
        options={{
          tabBarIcon: () => <Ionicons name="person" size={22} color="black" />,
        }}
      />
    </Tab.Navigator>
  );
};
export default BottomTabNavigator;
1 Answers

You are nesting a Tab.Navigator inside a Drawer.Navigator. Compare this with the following code snippet from your snack.

<Drawer.Screen
          name="Home"
          component={BottomTabNavigator}
          options={{
            title: 'Home',
            drawerIcon: ({color}) => <Ionicons name="home" size={22} color={color} />,
          }}
 />

This is not a problem but you need to keep in mind that nesting navigators change certain behaviors of your application, e.g.

Each navigator has its own options​. For example, specifying a title option in a screen nested in a child navigator won't affect the title shown in a parent navigator.

We can fix this by using the code provided in the official documentation of react-native for setting parent screen options based on child navigators state.

Here is what I have done in order to fix your title issue. In BottomTabNavigator.js:

const BottomTabNavigator = ({navigation, route}) => {

function getHeaderTitle(route) {
  const routeName = getFocusedRouteNameFromRoute(route) ?? 'Home';

  switch (routeName) {
    case 'Home2':
      return 'Home';
    case 'UserBookNewEvent':
      return 'Book Class';
    case 'UserProfilePage':
      return 'Profile';
  }
}

React.useLayoutEffect(() => {
    navigation.setOptions({ headerTitle: getHeaderTitle(route) });
  }, [navigation, route]);

...

Notice that our BottomTabNavigator is a child of the Drawer for the Home-Screen, thus it seems that both navigator navigate to the same screen while updating each others navigation states. This is not possible. We can see this, if we navigate via the Drawer to a different screen, then its title is now updated, however, the screen stays the same.

If it is desired to navigate via the Tab.Navigator if the user is on the Home-screen, such that both navigators stay visible, then this is possible. If the user navigates to a screen, different then the Home- screen via the Drawer, then the Tab.Navigator will vanish.

Thanks to the discussion from the comments, this is acceptable. Solving your second issue can be done with a little hack by setting the prop unmountOnBlur to true for the Home-screen provided in the DrawerNavigator as follows.

<Drawer.Screen
          name="Home"
          component={BottomTabNavigator}
          options={{
            title: 'Home',
            unmountOnBlur:true,
            drawerIcon: ({color}) => <Ionicons name="home" size={22} color={color} />,
          }}
 />

Please consider my updated snack for a full working solution.

Related