How to add firebase screen tracking analytics with React Native React Navigation when using createStackNavigator?

Viewed 2014

I have a React Native app and am using React Navigation. I am now trying to add screen tracking analytics with firebase.

I am following this documentation, which has this sample code:

import analytics from '@react-native-firebase/analytics';
import { NavigationContainer } from '@react-navigation/native';

<NavigationContainer
  ref={navigationRef}
  onStateChange={state => {
    const previousRouteName = routeNameRef.current;
    const currentRouteName = getActiveRouteName(state);

    if (previousRouteName !== currentRouteName) {
      analytics().setCurrentScreen(currentRouteName, currentRouteName);
    }

In my code, however, I am creating my base NavigationContainer with a function like so:

export default createStackNavigator(
  {
    Home: MainTabNavigator,
    SignIn: SignInNavigator,
  },
  {
    transitionConfig: dynamicModalTransition,
    headerMode: 'none',
    initialRouteName: 'Home',
  },
);

What is the best way to integrate the code from the example?

2 Answers

The problem is because you are on react-navigation v4.x.x, but the example you have is for v5.x.x.

In v4, event listeners can be added on AppContainer.

The example below is for v4.

import React from 'react';
import { createAppContainer, createStackNavigator } from 'react-navigation';

function getActiveRouteName(navigationState) {
    if (!navigationState) {
      return null;
    }
    const route = navigationState.routes[navigationState.index];

    if (route.routes) {
      return getActiveRouteName(route);
    }
    return route.routeName;
}

const nav = createStackNavigator({...});

const AppContainer = createAppContainer(nav);

export default () => {
    return <AppContainer
        onNavigationStateChange={(prevState, currentState, action) => {
            const currentRouteName = getActiveRouteName(currentState);
            const previousRouteName = getActiveRouteName(prevState);
      
            if (previousRouteName !== currentRouteName) {
              analytics().setCurrentScreen(currentRouteName, currentRouteName);
            }
          }}
    />
}

I'm using NavigationContainer and createStackNavigator, too and this is how I did it, like in the example for screen tracking at reactnavigation.org

import * as Analytics from 'expo-firebase-analytics';
import { useRef } from 'react';
import { NavigationContainer } from '@react-navigation/native';

export default () => {
  const navigationRef = useRef();
  const routeNameRef = useRef();

  return (
    <NavigationContainer
      ref={navigationRef}
      onReady={() =>
        (routeNameRef.current = navigationRef.current.getCurrentRoute().name)
      }
      onStateChange={async () => {
        const previousRouteName = routeNameRef.current;
        const currentRouteName = navigationRef.current.getCurrentRoute().name;

        if (previousRouteName !== currentRouteName) {
          // The line below uses the expo-firebase-analytics tracker
          // https://docs.expo.io/versions/latest/sdk/firebase-analytics/
          // Change this line to use another Mobile analytics SDK
          await analytics().logScreenView({
            screen_name: currentRouteName,
            screen_class: currentRouteName
          });
        }

        // Save the current route name for later comparison
        routeNameRef.current = currentRouteName;
      }}
    >
      {/* ... */}
    </NavigationContainer>
  );
};
Related