Reputation: 632
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.
Upvotes: 3
Views: 5295
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
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