Handling Notifications

Handling Notifications in the Foreground and Background

In the foreground, the handler from expo-notifications runs and addNotificationReceivedListener callbacks fire. In the background or killed, the system shows the notification without your JavaScript. A tap starts or resumes the app, and expo-notifications reports a response, where navigation belongs. useLastNotificationResponse() returns the latest response, including the one that cold-started the app, so a single hook in the root layout covers both cases:

src/notify/useNotifications.ts: opening the screen a notification points to (excerpt)TypeScript
export function useNotifications() {
  const router = useRouter();
  const last = Notifications.useLastNotificationResponse();   // survives a cold start
  // ...
  useEffect(() => {                                  // the user tapped a notification
    const url = last?.notification.request.content.data?.url;
    if (typeof url !== 'string') return;
    console.log('tapped:', url, '| action:', last?.actionIdentifier);
    router.push(url as Href);
  }, [last]);
}

RootStack in src/app/_layout.tsx calls it. Let data name a route rather than carry content, so the screen loads fresh data and the URL doubles as a deep link (Deep Links); treat it as untrusted input. Data-only pushes can run a background task (registerTaskAsync with expo-task-manager), but both platforms throttle them.