2

I am trying to navigate to a certain screen whenever I click on an Expo Push Notification. The screen that I want to navigate to is rather deep into the NavigationContainer.

However, the issue that I am facing now is being unable to even navigate to anywhere except having the app restart on its own. I'm running all the testing on a real device.

I'm using Expo to work on this school project.

I have only managed to find this question in SO and Expo Forums (duplicate) useful.

This is my application Navigation structure:

-Navigation Structure-

AppNavigator
  DrawerNavigator
    MainNavigator
      TabsNavigator
      StackNavigator
      StackNavigator
        TabsNavigator
          ScreenA (Want to navigate to)
          ScreenB (Want to navigate to)
        StackNavigator
          ScreenA
          ScreenB
      StackNavigator
    ScreenA
  AuthNavigator
  RegisterNavigator
  ScreenA

There is a useNotifications hook created and I called it in the main App Navigator where the NavigationContainer resides in.

import React, { useEffect } from 'react';
import * as Notifications from 'expo-notifications';

import navigation from '../navigation/RootNavigation';

const useNotifications = () => {
  const notiResponseListener = React.createRef();

  useEffect(() => {
    notiResponseListener.current =
      Notifications.addNotificationResponseReceivedListener(res => {
        console.log(res.notification.request.content.data);
        console.log('addNotificationResponseReceivedListener');

        navigation.navigate(
          ('DrawerNavigator', { screen: 'ChangePassword' }),
          {}
        );
      });

    return () =>
      Notifications.removeNotificationSubscription(notiResponseListener);
  }, []);
};

export default useNotifications;

There is a ref added to the NavigationContainer.

import { navigationRef } from '../navigation/RootNavigation';
import useNotifications from '../hooks/useNotifications';

const App = createStackNavigator();

const AppNavigator = () => {
  useNotifications();

  return (
    <NavigationContainer ref={navigationRef}>
      <App.Navigator headerMode='none'>
        ...
      </App.Navigator>
    </NavigationContainer>
  );
};

And lastly, the file that contains the ref used in the NavigationContainer.

import React from 'react';

export const navigationRef = React.createRef();

const navigate = (name, params) => {
  console.log('entered navigating'); // does not print
  navigationRef.current?.navigate(name, params);
};

export default {
  navigate
};

I have searced high and low but I can't seem to find out what's wrong. Looked at the documentation for Expo and React Navigation but I'm not sure what's going on. It's my first time working on Push Notifications and such a case.

I appreciate any help, thank you

domster
  • 556
  • 2
  • 8
  • 26
  • have you tried sending push while app is in foreground? when you click it does it restart the application? – denistepp Jul 01 '21 at 09:16
  • yes, it does restart the application. im referring to yours and testing again as we speak. sorry for bothering you, i literally cannot find any resource or help online from past posts or questions or threads – domster Jul 01 '21 at 09:18
  • upon clicking on the notification, it just immediately restarts the running application. i was wondering if you could spare a little time to speak with me over voice and i could share what's going on easily :/ thanks denistepp! EDIT: i have updated the codes over and over. for your reference please. i realise the `navigate` function isn't entered at all. – domster Jul 01 '21 at 09:30

1 Answers1

2

We have fixed the problem with the usage of useLastNotificationResponse.

    const [notification, setNotification] = useState(false);
    const notificationListener = useRef();
    const responseListener = useRef();

    //add this
    const lastNotificationResponse =
        Notifications.useLastNotificationResponse();

    useEffect(() => {
        if (lastNotificationResponse) {
            //console.log(lastNotificationResponse);

            //get the route
            const route = JSON.stringify(
                lastNotificationResponse.notification.request.content.data.route
            );

            //use some function to return the correct screen by route
            getFullPath(JSON.parse(route));
        }
    }, [lastNotificationResponse]);

Based on your routes, navigate to correct screen getFullPath:

import { navigationRef } from "./rootNavigation";
import routes from "./routes";

export function getFullPath(route) {
    switch (route) {
        case "HomeScreen":
            return navigationRef.current?.navigate(routes.HOME);
        case "Account":
            return navigationRef.current?.navigate(routes.ACCOUNT, {
                screen: routes.ACCOUNTSCREEN,
            });
        default:
            return;
    }
}

denistepp
  • 489
  • 7
  • 23