https://reactnavigation.org/docs/navigating-without-navigation-prop/
앞서 react-native firebase
로 푸시 알림을 구현했었습니다.
이 게시글의 4. 푸시 알림 수신 코드 작성을 참고해보시면,
앱이 켜져 있을 때, 즉 foreground
상태일 때에는 푸시 알림이 왔다는 걸
App.js
내부에서 잡아낼 수 있는데요.
// App.js
import React, { useEffect } from 'react';
import { Alert } from 'react-native';
import messaging from '@react-native-firebase/messaging';
function App() {
useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
// 앱이 foreground 인 상태에서 푸시 알림이 오면 이 안쪽을 탑니다.
// 기존에는 react-native 의 기본 Alert API 를 사용해 알럿을 띄워주도록 했어요.
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
return unsubscribe;
}, []);
}
위와 같이 코드를 작성하면, foreground
상태에서 푸시 알림을 수신했을 때 아래와 같은 창이 뜹니다.
저는 저 기본 Alert
대신, 커스텀으로 제작한 알럿 창을 띄워주고 싶었습니다.
그런데 우리 프로젝트의 custom alert 는 하나의 screen 으로 제작해 navigate
메서드를 통해 어디서든 띄워줄 수 있는 방식으로 컴포넌트화 해 놓았어요.
따라서 App.js
내부에서 navigate
메서드를 사용해야 하는 상황입니다.
일단 navigation
을 사용하려면 props
내부에 navigation
prop 이 있어야 하기에
콘솔에 props
를 찍어보았는데요, 빈 객체가 들어있습니다.
App.js
에는 navigation
prop 이 없는 거죠.
그래서
navigation
prop 이 없어도 navigate 할 수 있는 방법을 찾아보았습니다.
이 공식 문서의 내용을 참고해주세요.
위 공식 문서에 따르면, RootNavigation.js
라는 파일을 만들어서 navigationRef
를 export 시키고,
그 navigationRef
를 App.tsx
내부에서 NavigationContainer
의 ref
로 전달하는 방식이었다.
이렇게 적으니 복잡한 것 같지만 한 단계씩 따라하다보면 간단합니다.
RootNavigation.js
파일을 생성합니다.위치는 알아서! 저는 그냥 App.js
와 같은 위치에 만들었습니다.
// RootNavigation.js
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
NavigationContainer
의 ref
에 navigationRef
를 전달합니다.그런데 우리 프로젝트의 기존 코드에서는 NavigationContainer
가 App.tsx
가 아닌 RootStackNavigator.tsx
내부에 있었습니다.
Rootnavigator
의 RootStack.Navigator
를 감싸고 있네요.
아래가 기존 코드입니다.
// App.tsx
import RootNavigator from '../RootStackNavigator';
const App = () => {
return <RootNavigator />
}
// RootStackNavigator.tsx
import { NavigationContainer } from '@react-navigation/native';
const RootNavigator = props => {
<NavigationContainer>
<RootStack.Navigator>
{...}
</RootStack.Navigator>
</NavigationContainer>
}
그래서 NavigationContainer
를 App.tsx
로 옮겨주고, 거기다 ref
를 전달했습니다.
// App.tsx
import { NavigationContainer } from '@react-navigation/native';
import { navigationRef } from './RootNavigation';
import RootNavigator from '../RootStackNavigator';
const App = () => {
return (
<NavigationContainer ref={navigationRef}>
<RootNavigator />
</NavigationContainer>
)
}
App.tsx
내부에서 navigation 이 가능합니다.// App.tsx
import { NavigationContainer } from '@react-navigation/native';
import { navigationRef } from './RootNavigation';
import RootNavigator from '../RootStackNavigator';
const App = () => {
useEffect(() => {
const unsubscribe = messaging().onMessage(async (remoteMessage: any) => {
// 앱이 foreground 일 경우 push 알림이 오면 이 안쪽을 탑니다.
// 푸시 알림의 제목과 본문은 remoteMessage.notification 내부에 있으므로
// 해당 내용을 openPushNotification 함수에 인자로 넣어줍니다.
const { title, body } = remoteMessage.notification;
openPushNotification(title, body);
});
return unsubscribe;
}, []);
// custom alert 창을 띄우는 코드입니다.
// alert 에 띄울 정보를 params 에 담고,
// navigation prop 과 함께 alert 창을 띄우는 함수에 넘겨줍니다.
const openPushNotification = (title: string, body: string) => {
let params = {
title: title,
message: body,
{...}
};
// 원래 첫 번째 인자로 navigation prop 을 넘겨주도록 만들어놨는데,
// 여기선 그 대신 navigationRef.current 를 넘겨주면 됩니다.
ApplicationManager.showModal(navigationRef.current, params);
};
return (
<NavigationContainer ref={navigationRef}>
<RootNavigator />
</NavigationContainer>
)
}
그러면 이제 현재 사용자가 보고 있던 screen 이 어느 screen이든 간에
푸시 알림이 올 경우 해당 screen 에서 알림 내용을 custom alert 으로 띄워주는 코드가 완성되었습니다.
console.log(navigationRef.current?.getRootState().routes[0]);
App.tsx
이든 index.js
이든 navigation
prop 을 받아올 수 없는 곳이라면 어디에서든
위 내용을 콘솔 찍어 보세요.
아래와 같은 내용을 받아볼 수 있습니다.
현재 navigator
, 그리고 현재의 route
를 알 수 있죠!!
저는 navigator
정보만 필요했기 때문에
if (navigationRef.current?.getRootState().routes[0].name === 'LoginNavigator')
이런 식으로 사용했습니다.
많은 도움이 되었습니다,,