react-nativereact-hooksreact-navigationonfocusviewdidappear

react-navigation: Detect when screen, tabbar is activated / appear / focus / blur


Perviously when I wanted to make some actions when screen is opened I put them inside componentDidMount. For example I can fetch some data.

like this.

componentDidMount() {
  this.updateData();
}

But with react-navigation componentDidMount occurs only one time when user open screen first time, and if later user open this page again it will not trigger componentDidMount.

What is proper way to detect when page(screen) is activated and do actions?


Solution

  • React navigation v6

    Fetching data with an API call when a screen becomes focused

    React Navigation provides a hook that runs an effect when the screen comes into focus and cleans it up when it goes out of focus. This is useful for cases such as adding event listeners, for fetching data with an API call when a screen becomes focused, or any other action that needs to happen once the screen comes into view.

    import { useFocusEffect } from '@react-navigation/native';
    
    function ProfileScreen() {
      useFocusEffect(
        React.useCallback(() => {
    
          alert('Screen was focused');
    
          return () => {
    
            alert('Screen was unfocused');
            // Useful for cleanup functions
    
          };
        }, [])
      );
    
      return <View />;
    }
    

    A boolean indicating whether the screen is focused or not

    React Navigation provides a hook that returns a boolean indicating whether the screen is focused or not. The hook will return true when the screen is focused and false when our component is no longer focused. This enables us to render something conditionally based on whether the user is on the screen or not.

    import { useIsFocused } from '@react-navigation/native';
    
    function Profile() {
      const isFocused = useIsFocused();
    
      return <Text>{isFocused ? 'focused' : 'unfocused'}</Text>;
    }
    

    Ref v6.x: https://reactnavigation.org/docs/function-after-focusing-screen/


    Older:

    With react-navigation, you can do that in 2 steps:

    1. Add listeners in componentDidMountor componentWillMount, to hook events

    2. Remove listeners in componentWillUnmount , to avoid unexpected calling

    API Reference Documents v3.x, v4.x, v5.x

    React-navigation v3.x, v4.x:

    addListener - Subscribe to updates to navigation lifecycle

    React Navigation emits events to screen components that subscribe to them:

    • willFocus - the screen will focus
    • didFocus - the screen focused (if there was a transition, the transition completed)
    • willBlur - the screen will be unfocused
    • didBlur - the screen unfocused (if there was a transition, the transition completed)

    React-navigation 3.x, 4.x example:

    const didBlurSubscription = this.props.navigation.addListener(
      'didBlur',
      payload => {
        console.debug('didBlur', payload);
      }
    );
    
    // Remove the listener when you are done
    didBlurSubscription.remove();
    

    Ref v4.x https://reactnavigation.org/docs/4.x/navigation-prop/#addlistener---subscribe-to-updates-to-navigation-lifecycle

    UPDATED v5.x

    The events had been changed in v5.x

    Screens can add listeners on the navigation prop like in React Navigation. By default, there are 2 events available:

    • focus - This event is emitted when the screen comes into focus
    • blur - This event is emitted when the screen goes out of focus
    • state (advanced) - This event is emitted when the navigator's state changes

    Sample code from reactnavigation.org

    class Profile extends React.Component {
      componentDidMount() {
        this._unsubscribe = navigation.addListener('focus', () => {
          // do something
        });
      }
    
      componentWillUnmount() {
        this._unsubscribe();
      }
    
      render() {
        // Content of the component
      }
    }
    

    Use with hook

    function Profile({ navigation }) {
      React.useEffect(() => {
        const unsubscribe = navigation.addListener('focus', () => {
          // do something
        });
    
        return unsubscribe;
      }, [navigation]);
    
      return <ProfileContent />;
    }
    

    Listeners prop on Screen

    <Tab.Screen
      name="Chat"
      component={Chat}
      listeners={({ navigation, route }) => ({
        tabPress: e => {
          // Prevent default action
          e.preventDefault();
    
          // Do something with the `navigation` object
          navigation.navigate('AnotherPlace');
        },
      })}
    />
    

    Ref v5.x: https://reactnavigation.org/docs/navigation-events