참고 링크
Push Notifications with Firebase in React.js
현재 코드에서 onMessageListener 함수가 새 알림 메시지가 수신되면 해당 메시지의 제목과 내용을 notification state에 저장하고, 해당 state가 업데이트될 때 notify() 함수를 호출하여 토스트 알림을 보여주도록 구현되어 있습니다.
따라서, Notification 컴포넌트는 이미 알림이 오면 notification state가 업데이트되어 토스트 알림이 표시되도록 되어 있습니다. ⇒ 그런데 왜 안될까? 🤷🏻♀️
//firebase.ts
import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';
import { VAPID_KEY } from '../constant/union';
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
};
const app = initializeApp(firebaseConfig);
export const foregroundMessaging = getMessaging(app);
export async function getFcmToken() {
console.log('권한 요청 중...');
const permission = await Notification.requestPermission();
if (permission === 'denied') {
console.log('알림 권한 허용 안됨');
return;
}
console.log('알림 권한이 허용됨');
const token = await getToken(foregroundMessaging, {
vapidKey: VAPID_KEY,
});
return token;
}
// onMessage 이벤트가 발생할 때마다 payload 인자를 Promise의 해결 값으로 반환 => 앱에서 FCM 푸시 알림 메시지 처리 O
// 이 함수를 사용하여 앱이 포그라운드에 있을 때 FCM에서 수신된 푸시 알림 메시지를 처리할 수 있습니다. => 왜 안됨?
export const onMessageListener = () =>
new Promise((resolve) => {
onMessage(foregroundMessaging, (payload) => {
console.log('payload', payload);
resolve(payload);
});
});
// foregroundNotification.tsx
import { useEffect, useState } from 'react';
import toast, { Toaster } from 'react-hot-toast';
import { getFcmToken, onMessageListener } from './firebase';
// 앱에서 푸시 알림을 표시하는 컴포넌트
const foregroundNotification = () => {
const [notification, setNotification] = useState({ title: '', body: '' });
const notify = () => toast(<ToastDisplay />);
function ToastDisplay() {
return (
<div>
<p>
<b>{notification?.title}</b>
</p>
<p>{notification?.body}</p>
</div>
);
}
useEffect(() => {
getFcmToken();
}, []);
// (parameter) payload: unknown 개체가 '알 수 없는' 형식입니다.
useEffect(() => {
onMessageListener()
.then((payload) => {
setNotification({ title: payload?.notification?.title, body: payload?.notification?.body });
})
.catch((err) => console.log('failed: ', err));
}, []);
useEffect(() => {
if (notification?.title) {
notify();
}
}, [notification]);
return <Toaster />;
};