TJ Gillis
TJ Gillis

Reputation: 507

React Navigation on tab change

Without using Redux, how do I detect a tab change with a react navigation tab navigator?

I know I need to somehow use onNavigationStateChange but I can't figure out how to update the current view.

export default () => <MyTabNav
    ref={(ref) => { this.nav = ref; }}
    onNavigationStateChange={(prevState, currentState) => {
        //call function on current view
    }}
/>;

Upvotes: 15

Views: 34234

Answers (6)

Carter
Carter

Reputation: 306

You can add a focus listener to each screen. This will activate not just when the tab is pressed by also when swiped to or programatically shown.

<Tab.Navigator>
    <Tab.Screen
        component={HomeScreen}
        name="HomeScreen"
        listeners={{
            focus: e => {
                alert('focused')
            }
        }}
    />
</Tab.Navigator>

Tested with react-navigation 6.

Upvotes: 1

Sanjeev
Sanjeev

Reputation: 4375

If you are using react-navigation version 5 or higher, then you can add tab-press listener right in your tab screen definition, to do some pre-processing, as mentioned in docs

<Tab.Navigator>
    <Tab.Screen
        component={HomeScreen}
        name="HomeScreen"
        listeners={{
          tabPress: e => {
            if (userIsNotLoggedIn) {
              // Prevent default action
              e.preventDefault();
              navigation.navigate("LoginScreen");
            }
          },
        }}
      />
      <Tab.Screen
        ../>
</Tab.Navigator>

Explanation: When Home tab will be clicked in BottomBar, and if user is not logged in, the HomeScreen won't open and instead LoginScreen will open(Note: LoginScreen is navigation name which will be registered some where with a screen). But if user is logged in, then it will behave normally.

As of react-navigation v6, you may also place a tabPress listener on the <Tab.Navigator>, via the screenListeners property.

Upvotes: 12

Arun Kumar
Arun Kumar

Reputation: 355

And if you intend to use the Window properties, you can easily do this in react.

Keep a check whether window is present before return inside of render.

if (typeof window !== "undefined") {
window.addEventListener('visibilitychange, () => {
window.document.title = window.document.hidden;
console.log(document.hidden ? "Out" : "In");
this.props.doFunction();

}

Upvotes: 1

OsDev
OsDev

Reputation: 1252

Actually, you can add an special listener in your component

componentDidMount () {
    this.props.navigation.addListener('willFocus', (route) => { //tab changed });
} 

Upvotes: 36

bumbur
bumbur

Reputation: 311

export default () => <MyTabNav
    ref={(ref) => { this.nav = ref; }}
    onNavigationStateChange={(prevState, currentState) => {
       const getCurrentRouteName = (navigationState) => {
         if (!navigationState) return null;
         const route = navigationState.routes[navigationState.index];
         if (route.routes) return getCurrentRouteName(route);
         return route.routeName;
       };
    global.currentRoute = getCurrentRouteName(currentState);
  }}
/>;

If you don't want to use redux, this is how you can store global information about the current route, so you can both detect a tab change and also tell which tab is now active.

Upvotes: 5

Val
Val

Reputation: 22797

There's some long discussions about this from react-native issue 314, 486, 1335, and finally we got a better built in way to handle this, after Sep 27, 2017, react-navigation version v1.0.0-beta.13:

New Features

Accept a tabBarOnPress param (#1335) - @cooperka

Usage:

const MyTabs = TabNavigator({
  ...
}, {
  tabBarComponent: TabBarBottom /* or TabBarTop */,
  tabBarPosition: 'bottom' /* or 'top' */,
  navigationOptions: ({ navigation }) => ({
    tabBarOnPress: (scene, jumpToIndex) => {
      console.log('onPress:', scene.route);
      jumpToIndex(scene.index);
    },
  }),
});

Upvotes: 5

Related Questions