This is needed only for the ios distribution of the app and results in rejected app if you don't have it, but have selected in your app privacy information in App Store Connect that you track users - think analytics, advertising, Sentry, Crashlytics...

I use app.config.ts and it looks something like:

const config: ExpoConfig = {
  ios: {
    infoPlist: {
      NSUserTrackingUsageDescription: 'This identifier will be used to deliver personalized ads to you.',
    },
  },
  plugins: [
    [
      'react-native-permissions',
      {
        iosPermissions: ['AppTrackingTransparency'],
      },
    ],
  ]
}

First is NSUserTrackingUsageDescription, which is a message that informs the user why an app is requesting permission to use data for tracking the user or the device.

Second is the permission that we need from the user, and for that I'm using the react-native-permissions library.

The part that actually calls the permission is:

import { useEffect } from 'react';
import { Platform } from 'react-native';
import { PERMISSIONS, request, RESULTS } from 'react-native-permissions';

const delay = (ms: number | undefined): Promise<number> => new Promise((res) => setTimeout(res, ms));

type ResultHandler = (granted: boolean) => PromiseLike<void>;

const useAppTrackingTransparency = (onResult: ResultHandler) => {
  useEffect(() => {
    (async () => {
      if (Platform.OS === 'ios') {
        const timeoutId = await delay(1000);
        const result = await request(PERMISSIONS.IOS.APP_TRACKING_TRANSPARENCY);
        await onResult(result === RESULTS.GRANTED);
        return () => {
          clearTimeout(timeoutId);
        };
      } else {
        await onResult(true);
      }
    })();
  }, []);
};

export default useAppTrackingTransparency;

I can't explain really why the delay, except that it was me doing trial and error.

Without it, the ATT popup window wouldn't show. Why the 1 second, it's an arbitrary number I chose.

I call the hook as soon as the app starts (_layout.ts):

useAppTrackingTransparency(async (granted) => {
  if (granted) {
    await analytics().setAnalyticsCollectionEnabled(true);
  } else {
    await analytics().setAnalyticsCollectionEnabled(false);
  }
});
ATT popup