Bowis
Bowis

Reputation: 632

Override Header Title React Navigation V5

I have created a nested tab navigator in my stack navigator as follows:

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

function TabNav () {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen}></Tab.Screen>
      <Tab.Screen name="Category" component={CategoryScreen}></Tab.Screen>
      <Tab.Screen name="Settings" component={SettingsScreen}></Tab.Screen>
    </Tab.Navigator>
  )
} 

export default function App() {
  return (
    <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen name="Tab" component={TabNav}></Stack.Screen>
          <Stack.Screen name="Category" component={CategoryScreen}>
          </Stack.Screen>
          <Stack.Screen
            name="SpecialBeerScreen" component= {SpecialBeerScreen}>
          </Stack.Screen>
        </Stack.Navigator>
    </NavigationContainer>
  )
}

However, the header now looks like Tab for each of the screens. How do I override this Header for each of the screens with a custom text, such as Home, Category etc.

enter image description here

Upvotes: 3

Views: 5295

Answers (2)

Andru
Andru

Reputation: 6184

Update: This is still valid in react-navigation v6


Use getFocusedRouteNameFromRoute as outlined in the react-navigation docs in the section Setting parent screen options based on child navigator's state to access information of screens in nested navigators.

Change this line

<Stack.Screen name="Tab" component={TabNav}></Stack.Screen>

to the following (adding the options prop):

<Stack.Screen
  name="Tab"
  component={TabNav}
  options={({ route }) => {
    const routeName = getFocusedRouteNameFromRoute(route) ?? 'Home';

    switch (routeName) {
      case 'Category': {
        return {
          headerTitle: 'Category',
        };
      }
      case 'Settings': {
        return {
          headerTitle: 'Settings',
        };
      }
      case 'Home':
      default: {
        return {
          headerTitle: 'Home',
        };
      }
    }
  }}
/>

You also have to import getFocusedRouteNameFromRoute, so also add:

import { getFocusedRouteNameFromRoute } from '@react-navigation/native';

Upvotes: 8

gie3d
gie3d

Reputation: 809

If I understand your problem correctly, you wanted to change the stack title when the tab is changed. In this case, you may use React Context to control it.

(I also put this code in snack https://snack.expo.io/@gie3d/change-header-from-tab)

edit: 1, I separated it into 3 files and assume that it's all in the same directory.

HomeTitleContext.js

export const HomeTitleContext = React.createContext({
    title: 'default title',
    setTitle: () => {},
});

App.js

import { HomeTitleContext } from './HomeTitleContext';

export default function App() {
    const [title, setTitle] = useState('default title');
    return (
        <HomeTitleContext.Provider
            value={{
                title,
                setTitle,
            }}
        >
            <HomeTitleContext.Consumer>
                {(ctx) => (
                    <NavigationContainer>
                        <Stack.Navigator>
                            <Stack.Screen
                                name="Tab"
                                component={TabNav}
                                options={{ title: ctx.title }} // The title will be dynamically changed here
                            />
                            <Stack.Screen
                                name="Category"
                                component={OtherScreen}
                            ></Stack.Screen>
                            <Stack.Screen
                                name="SpecialBeerScreen"
                                component={OtherScreen}
                            ></Stack.Screen>
                        </Stack.Navigator>
                    </NavigationContainer>
                )}
            </HomeTitleContext.Consumer>
        </HomeTitleContext.Provider>
    );
}

In your component, for example: HomeScreen, you set up a useFocusEffect and change the title from setTitle which you'll get from the context

HomeScreen.js

import React, { useContext } from 'react';
import { useFocusEffect } from '@react-navigation/native';
import { View, Text } from 'react-native';

import { HomeTitleContext } from './HomeTitleContext';

const HomeScreen = ({ navigation }) => {
    const { setTitle } = useContext(HomeTitleContext);
    useFocusEffect(() => {
        setTitle('this is home');
    });

    return (
        <View>
            <Text>Home</Text>
        </View>
    );
};

Upvotes: 3

Related Questions