Search code examples
react-nativereact-native-navigationreact-native-router-flux

Programatically hiding and showing individual tabs in React Native Router Flux Tabbar


I have a tabbar in my app using React Native Router Flux. There are a couple use cases where hiding or showing specific tabs based on the current user would be very helpful. The main ones I have run into are:

  • AB testing new tabs to specific users
  • Showing a special admin tab to certain users with certain privileges

The react-native-router-flux library does not support any options to do this from what I can see. How can I achieve this functionality?


Solution

  • The default tabbar component in react-native-router-flux is just the component from the react-navigation-tabs library. You can import this component directly into your code, customize as needed, and then pass it to react-native-router-flux through the tabBarComponent prop (documented here).

    I created a new component, which you should be able to copy directly and just change the logic for actually hiding the tabs based on your state:

    import React from 'react'
    import { BottomTabBar } from 'react-navigation-tabs'
    import { View, TouchableWithoutFeedback } from 'react-native'
    import { connect } from 'react-redux'
    
    const HiddenView = () => <View style={{ display: 'none' }} />
    const TouchableWithoutFeedbackWrapper = ({
      onPress,
      onLongPress,
      testID,
      accessibilityLabel,
      ...props
    }) => (
      <TouchableWithoutFeedback
        onPress={onPress}
        onLongPress={onLongPress}
        testID={testID}
        hitSlop={{
          left: 15,
          right: 15,
          top: 5,
          bottom: 5,
        }}
        accessibilityLabel={accessibilityLabel}
      >
        <View {...props} />
      </TouchableWithoutFeedback>
    )
    const TabBarComponent = props => (
      <BottomTabBar
        {...props}
        getButtonComponent={({ route }) => {
          if (
            (route.key === 'newTab' && !props.showNewTab) ||
            (route.key === 'oldTab' && props.hideOldTab)
          ) {
            return HiddenView
          }
          return TouchableWithoutFeedbackWrapper
        }}
      />
    )
    
    export default connect(
      state => ({ /* state that you need */ }),
      {},
    )(TabBarComponent)
    

    And then simply imported and used that in my Tabs component:

    <Tabs
      key="main"
      tabBarComponent={TabBarComponent} // the component defined above
      ...
    

    Detailed look at where these things are getting passed to

    Looking at the line of the source of react-native-router-flux, it is using createBottomTabNavigator from the react-navigation library, and passing no component if you do not pass a custom tabBarComponent. The createBottomTabNavigator method in react-navigation comes from this line of the library, and is actually defined in react-navigation-tabs. Now, we can here see in react-navigation-tabs that if no tabBarComponent has been passed, it simply uses BottomTabBar, also defined in react-navigation-tabs. This BottomTabBar, in turn, takes a custom tab button renderer through props, called getButtonComponent.