'Get the current active screen route of the tab navigator in react navigation

This is my navigation stack using react navigation v3.2.1:

  1. I have a switch navigator to switch to Authentication navigation stack and Authenticated App stack.

  2. The App stack is made using a bottom tab navigator.

  3. I would like to use a custom component for the tab navigator.

How do I get the current routeName of the tab navigator when using createBottomTabNavigator and a custom tabBarComponent.

Eg:

  1. Suppose the tab navigation stack has 2 navigation screens, i.e., Home and Chat.
  2. Inside the custom BottomBar, how do I check if the focused/active/current routeName is Home/Chat so that I can change the style of icons respectively?

AppContainer.js

const switchStack = createSwitchNavigator({
    AuthLoading: AuthLoadingScreen,
    App: AppStack,
    Auth: AuthStack
}, {
    initialRouteName: 'AuthLoading',
})

export default createAppContainer(switchStack)

AppStack.js

const AppStack = createBottomTabNavigator({
    Home: {
        screen: HomeStack,
    },
    Chat: {
        screen: ChatStack
    },
}, {
    initialRouteName: 'Home',
    activeColor: '#f0edf6',
    inactiveColor: '#3e2465',
    shifting: false,
    barStyle: {
        backgroundColor: '#694fad',
    },
    labeled: false,
    tabBarComponent: ({navigation}) => <BottomBar navigation={navigation}/>
})

export default AppStack

BottomBar.js

export default class BottomBar extends React.Component {
    constructor(props) {
        super(props)
    }

    render() {
        return (
            <View style={styles.container}>
                <IconComponent routeName={'Home'}/>
                <IconComponent routeName={'Chat'}/>
            </View>
        )
    }
}

IconComponent.js

export default class IconComponent extends React.Component {
    constructor(props) {
        super(props)
    }

    ...

    render() {
        let IconComponent
        let iconName
        let iconSize = 25
        switch (this.props.routeName) {
            case 'Home':
                IconComponent = MaterialCommunityIcons
                // iconName = `home${focused ? '' : '-outline'}`;
                iconName = `home`;
                break
            case 'Chat':
                IconComponent = AntDesign
                iconName = `message1`
                iconSize = 22
                break
        }

        let tintColor = 'green'

        // if focused Home is current tab screen then change style eg. tint color.
        // similary if current tab screen is Chat, then change style.

        return (
                <Animated.View
                    style={[
                        styles.container,
                        {
                            opacity: this.opacity
                        }
                    ]}
                >
                    <IconComponent name={iconName} size={iconSize} color={tintColor}/>
                </Animated.View>
        )
    }
}


Solution 1:[1]

navigation object of your custom BottomBar has an index that hold the current active screen index

tabBarComponent: ({navigation}) => <BottomBar navigation={navigation}/>

navigation.state.index

If Home screen is active >> navigation.state.index would be 0 If Chat screen is active >> navigation.state.index would be 1 ...etc

Solution 2:[2]

Rather than setting a complete new tabBarComponent for icons you can use tabBarIcon property to set the icons. You can find an example on Tab Navigation Docs

  • tabBarIcon is a property on navigationOptions, so we know we can use it on our screen components, but in this case chose to put it in the createBottomTabNavigator configuration in order to centralize the icon configuration for convenience.
  • tabBarIcon is a function that is given the focused state, tintColor, and horizontal param, which is a boolean. If you take a peek further down in the configuration you will see tabBarOptions and activeTintColor and inactiveTintColor. These default to the the iOS platform defaults, but you can change them here. The tintColor that is passed through to the tabBarIcon is either the active or inactive one, depending on the focused state (focused is active). The orientation state horizontal is true when the device is in landscape, otherwise is false for portrait.
  • Read the full API reference for further information on createBottomTabNavigator configuration options.

Example (From the docs)

export default createBottomTabNavigator(
  {
    Home: HomeScreen,
    Settings: SettingsScreen,
  },
  {
    defaultNavigationOptions: ({ navigation }) => ({
      tabBarIcon: ({ focused, horizontal, tintColor }) => {
        const { routeName } = navigation.state;
        let IconComponent = Ionicons;
        let iconName;
        if (routeName === 'Home') {
          iconName = `ios-information-circle${focused ? '' : '-outline'}`;
          // Sometimes we want to add badges to some icons. 
          // You can check the implementation below.
          IconComponent = HomeIconWithBadge; 
        } else if (routeName === 'Settings') {
          iconName = `ios-options${focused ? '' : '-outline'}`;
        }

        // You can return any component that you like here!
        return <IconComponent name={iconName} size={25} color={tintColor} />;
      },
    }),
    tabBarOptions: {
      activeTintColor: 'tomato',
      inactiveTintColor: 'gray',
    },
  }
);

Solution 3:[3]

You can with navigation.state.routeName

tabBarComponent: ({navigation}) => <BottomBar navigation={navigation} currentRouteName={navigation.state.routeName} />

Or Better still you can do something like this:

const TabNavigator = createBottomTabNavigator({
    Home: Home,
    Chat: Chat
},
{
    defaultNavigationOptions: ({ navigation }) => ({
        tabBarIcon: ({ focused, horizontal, tintColor }) => {
            if (navigation.state.routeName === 'Home') {
                return <Icon name='ios-home' size={30} color={tintColor} />
            } else if (navigation.state.routeName === 'Chat') {
                return <Icon name='ios-heart' size={30} color={tintColor} />
            }
        },
        tabBarOptions: {
            activeTintColor: '#2BEDBA',
            inactiveTintColor: '#FAFAFA',
            style: { backgroundColor: '#000', paddingTop: 5 }
        },
    })
});

Solution 4:[4]

Using a functional component with React Navigation 5.x. You can use the useIsFocused hook.

import { useIsFocused } from "@react-navigation/native"; 

Usage: In each of the tab screens that you want to detect if they are the currently active or focused.

const isFocused = useIsFocused();

if (isFocused) {
  // the screen is currently focused
  // your code here
}

Docs: https://reactnavigation.org/docs/function-after-focusing-screen/

Solution 5:[5]

As @Biskrem Muhammad suggested, this works:

export function SignUp(props: TSignupProps) {
  const { navigation, route } = props;
  console.log('Im in screen:', route.name)
  .
  .
  .
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 bennygenel
Solution 3
Solution 4 Hackman
Solution 5 jonyB