import { useEffect, useLayoutEffect, useState } from 'react'; import { NotificationResponse } from './Notifications.types'; import { addNotificationResponseReceivedListener } from './NotificationsEmitter'; import NotificationsEmitterModule from './NotificationsEmitterModule'; /** * A React hook always returns the notification response that was received most recently * (a notification response designates an interaction with a notification, such as tapping on it). * * > If you don't want to use a hook, you can use `Notifications.getLastNotificationResponseAsync()` instead. * * @return The hook may return one of these three types/values: * - `undefined` - until we're sure of what to return, * - `null` - if no notification response has been received yet, * - a [`NotificationResponse`](#notificationresponse) object - if a notification response was received. * * @example Responding to a notification tap by opening a URL that could be put into the notification's `data` * (opening the URL is your responsibility and is not a part of the `expo-notifications` API): * ```jsx * import * as Notifications from 'expo-notifications'; * import { Linking } from 'react-native'; * * export default function App() { * const lastNotificationResponse = Notifications.useLastNotificationResponse(); * React.useEffect(() => { * if ( * lastNotificationResponse && * lastNotificationResponse.notification.request.content.data.url && * lastNotificationResponse.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER * ) { * Linking.openURL(lastNotificationResponse.notification.request.content.data.url); * } * }, [lastNotificationResponse]); * return ( * // Your app content * ); * } * ``` * @header listen */ export default function useLastNotificationResponse() { const [lastNotificationResponse, setLastNotificationResponse] = useState< NotificationResponse | null | undefined >(undefined); // useLayoutEffect ensures the listener is registered as soon as possible useLayoutEffect(() => { const subscription = addNotificationResponseReceivedListener((response) => { setLastNotificationResponse(response); }); return () => { subscription.remove(); }; }, []); // On each mount of this hook we fetch last notification response // from the native module which is an "always active listener" // and always returns the most recent response. useEffect(() => { NotificationsEmitterModule.getLastNotificationResponseAsync?.().then((response) => { // We only update the state with the resolved value if it's empty, // because if it's not empty it must have been populated by the `useLayoutEffect` // listener which returns "live" values. setLastNotificationResponse((currentResponse) => currentResponse ?? response); }); }, []); return lastNotificationResponse; }