I want to change the bottom tabs on the screen based on what features are enabled. This feature list is populated via a login API call.
Currently I have the following:
const TabRouteConfig = {
Home: DashboardScreen,
FeatureA: FeatureA,
FeatureZ: FeatureZ,
};
const TabNavigatorConfig = {
initialRouteName: 'Home',
order: [
'Home',
'Feature A',
],
tabBarPosition: 'bottom',
lazy: true,
};
const TabNavigator1 = createBottomTabNavigator(
TabRouteConfig,
TabNavigatorConfig,
);
// Set the tab header title from selected route
// https://reactnavigation.org/docs/en/navigation-options-resolution.html#a-stack-contains-a-tab-navigator-and-you-want-to-set-the-title-on-the-stack-header
TabNavigator1.navigationOptions = ({ navigation }) => {
const { index, routes } = navigation.state;
const { routeName } = routes[index];
return {
headerTitle: routeName,
};
};
const TabNavigator2 = createBottomTabNavigator(
TabRouteConfig,
{
...TabNavigatorConfig,
order: [
'Home',
'Feature Z',
]
);
TabNavigator2.navigationOptions = TabNavigator1.navigationOptions;
const Stack = createStackNavigator({
Main: {
screen: props => (props.screenProps.hasFeature ?
<TabNavigator1 /> : <TabNavigator2 />
)
},
})
const WrappedStack = props => (
<View style={styles.container}>
<Stack
screenProps={{ hasFeature: props.hasFeature }}
/>
</View>
);
const mapStateToProps = (state, props) => {
return {
...props,
hasFeature: state.hasFeature,
};
};
export default connect(mapStateToProps, null)(WrappedStack);
This mostly works - it dynamically switches between TabNavigator1
and TabNavigator2
based on hasFeature
, but it no longer honors the navigationOptions
placed on the TabNavigators and the headerTitle
is not set.
Is there a better way to do this?
Add icons to the tab bar To add icons to each tab, first import the Icon component from react-native-vector-icons library inside the navigation/TabNavigator/index. js file. For this example, let's use AntDesign based icons. // after other import statements import Icon from 'react-native-vector-icons/AntDesign';
Tab navigator nested inside the initial screen of stack navigator - New screens cover the tab bar when you push them. Drawer navigator nested inside the initial screen of stack navigator with the initial screen's stack header hidden - The drawer can only be opened from the first screen of the stack.
It's an antipattern to render more than one navigator simultaneously as the navigation states of those navigators will be completely separated, and you will not be able to navigate to one from another.
You can use tabBarComponent
option to achieve what you want. Hope you can get the idea from below example:
import { createBottomTabNavigator, BottomTabBar } from 'react-navigation-tabs';
const TabNavigator = createBottomTabNavigator(
TabRouteConfig,
{
tabBarComponent: ({ navigation, ...rest }) => {
const filteredTabNavigatorRoutes = navigation.state.routes.filter(route => isRouteAllowed(route));
return (
<BottomTabBar
{...rest}
navigation={{
...navigation,
state: { ...navigation.state, routes: filteredTabNavigatorRoutes },
}}
/>
);
},
},
);
NOTES:
react-navigation-tabs
separately. It is automatically installed with react-navigation
2.0.0+.isRouteAllowed
is the function which returns true
or false
based on whether to show that route or not. Make sure to only check the top level routes in that object.TabRouteConfig
should contain all possible tabs, and this logic only hides the route from the TabBar visually. So, you can still programmatically navigate to all routes. Therefore, you might need additional logic in each of those screens to decide whether to render them based on hasFeature
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With