Search code examples
javascriptreactjsreact-nativereact-native-navigation

How can you call a function on any navigation event in React Native?


My use case:

We are trying to implement an inactivity timeout for a react native app. We would like the timeout to refresh when a user interacts with the app, as well as when navigating between screens.

Currently, on a user interaction event the resetInactivityTimeout() callback function is triggered. We are trying to also trigger this callback on any navigation event. In our case, this is when a loading screen has gotten data it needed and pushes a new screen onto the navigation stack.

App.js contains our Navigators, the Timer, and the reset timer callback

import UserInactivity from 'react-native-user-inactivity';
...
const MainNavigator = createStackNavigator(
    // Screen Definitions 
)

const App = createAppContainer(MainNavigator);



export default function () {

   const resetInactivityTimeout = useCallback(() => {
       // reset logout timer
   }

   return ( 
        <UserInactivity
          timeForInactivity={500}
          onAction={(isActive) => {
              if (isActive && !modalVisible) {
                   resetInactivityTimeout();
             }
          }}>
              <App
              ref={(nav) => {
                 navRef.current = nav;
              }}/>
       </UserInactivity>
  )
}
...

I believe it should be something along the lines of setting App's onNavigationEvent to resetInactivityTimeout() or something like that, but I can't figure out how to do that...

Thanks in advance for any suggestions!

Note:

I'm working with react-navigation V4


Solution

  • The React Navigation V4 Documentation on App Containers gives information about several useful navigator methods

    onNavigationStateChange exposes the API for all navigation state change events

    From the Docs

    onNavigationStateChange(prevState, newState, action)​

    Function that gets called every time navigation state managed by the navigator changes. It receives the previous state, the new state of the navigation and the action that issued state change. By default it prints state changes to the console.

    Example usage:

    import React from 'react';
    import { createAppContainer } from 'react-navigation';
    import { createStackNavigator } from 'react-navigation-stack';
    
    const MainNavigator = createStackNavigator(
      {
         ... // Screens
       }
    const App = createAppContainer(MainNavigator);
    
    export default function () {
    
      return (
                <App
                  ref={(nav) => {
                    navRef.current = nav;
                  }}
                  onNavigationStateChange={(newState) => console.log('state updated:' , newState)}
                ></App>
      )
    }
    

    Might be worth mentioning that React Navigation V5 forward no longer uses createAppContainer so you do not interact with navigation state change events in the same way.

    After React Navigation V4, AppContainer was was abandoned for the NavigationContainer as the top-level container and the onStateChange prop functions similarly to AppContainer's onNavigationStateChange event, shown below

    import * as React from 'react';
    import { NavigationContainer } from '@react-navigation/native';
    
    export default function App() {
      return (
        <NavigationContainer onStateChange={()=> console.log(do something)}>
           {/* Rest of your app code */}. 
        </NavigationContainer>
      );
    }