Basically the issue is that – I have a NotificationHandler
that registers and handles remote/push notifications. When I render the NotificationHandler
outside the NavigationContainer
of @react-navigation/native
, the NotificationHandler
stops working. It registers for Push Notification, but does not receive the notification or display it. However, when I render the NotificationHandler
somewhere within the children of NavigationContainer
it works! But! It only works unless you switch the tabs, once you switch the tab, the notifications stop showing up.
For the NotificationHandler
, the code below uses [email protected]
, however, for the major part of the development I had been using [email protected]
library.
import { useEffect } from 'react'
import {
Notification,
NotificationCompletion,
Notifications,
Registered,
RegistrationError,
} from 'react-native-notifications'
function NotificationHandler() {
useEffect(() => {
Notifications.registerRemoteNotifications()
console.log('NotificationHandler registered')
Notifications.events().registerRemoteNotificationsRegistered(
(event: Registered) => {
// TODO: Send the token to my server so it could send back push notifications...
console.log('Device Token Received', event.deviceToken)
}
)
Notifications.events().registerRemoteNotificationsRegistrationFailed(
(event: RegistrationError) => {
console.error(event)
}
)
Notifications.events().registerNotificationReceivedForeground(
(
notification: Notification,
completion: (response: NotificationCompletion) => void
) => {
console.log('Notification Received - Foreground', notification.payload)
// Calling completion on iOS with `alert: true` will present the native iOS inApp notification.
completion({ alert: true, sound: true, badge: false })
}
)
Notifications.events().registerNotificationOpened(
(notification: Notification, completion: () => void, action: any) => {
console.log('Notification opened by device user', notification.payload)
console.log(
`Notification opened with an action identifier: ${action.identifier} and response text: ${action.text}`
)
completion()
}
)
Notifications.events().registerNotificationReceivedBackground(
(
notification: Notification,
completion: (response: NotificationCompletion) => void
) => {
console.log('Notification Received - Background', notification.payload)
// Calling completion on iOS with `alert: true` will present the native iOS inApp notification.
completion({ alert: true, sound: true, badge: false })
}
)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return null
}
export default NotificationHandler
The above is basically straight from the docs, no changes whatsoever.
The NotificationHandler
is rendered within the NavigationContainer
which has a StackNavigator
as the parent screen and a nested TabNavigator
within one of the stack screens.
import {
NavigationContainer,
createNavigationContainerRef,
} from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import React, { useEffect, useState } from 'react'
import { Alert, LogBox, Platform, StatusBar } from 'react-native'
import InitialChecksHandler from 'screens/Login/components/InitialChecksHandler'
import Maintenance from 'screens/Maintenance/Maintenance'
import Splash from 'screens/Splash/Splash'
import type { InitialChecksResult, RootStackParamList } from 'utils/types'
import { AUTH_STATUS_MAP } from 'app/constant'
import { useAuthContext } from '../context/AuthContext'
import AuthStackNavigator from '../routes/Auth/Auth'
import MainTabNavigator from '../routes/Main/Main'
import NotificationHandler from './NotificationHandler'
const Stack = createNativeStackNavigator<RootStackParamList>()
LogBox.ignoreLogs([
'Non-serializable values were found in the navigation state',
])
export const navigationRef = createNavigationContainerRef<RootStackParamList>()
// Need to disable type check here
// (Please check the declaration of navigationRef.navigate to understand why)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function navigate(name: any, params: any) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params)
}
}
function RootRoutes() {
const { authStatus } = useAuthContext()
return (
<>
<StatusBar backgroundColor="#0090DA" barStyle="light-content" />
<Stack.Navigator
initialRouteName="Auth"
screenOptions={{ headerShown: false }}
>
{authStatus === AUTH_STATUS_MAP.LOGGED_IN ? (
<Stack.Screen name="Main" component={MainTabNavigator} />
) : (
<Stack.Screen name="Auth" component={AuthStackNavigator} />
)}
<Stack.Screen
name="Maintenance"
component={Maintenance}
options={{ headerShown: false }}
/>
</Stack.Navigator>
</>
)
}
function RootNavigator(): React.JSX.Element {
const [initialCheckResults, setInitialCheckResults] =
useState<InitialChecksResult | null>(null)
if (!initialCheckResults) {
return <Splash setResults={setInitialCheckResults} />
}
return (
<NavigationContainer ref={navigationRef}>
<InitialChecksHandler
setInitialCheckResults={setInitialCheckResults}
{...initialCheckResults}
/>
<NotificationHandler />
<RootRoutes />
</NavigationContainer>
)
}
export default RootNavigator
Please let me know if there is need for additional information. Thank you and any help is appreciated since I have been banging my head on this for over a week now.