React+Firebase:失焦时将SW消息传递至Notification组件
React中Firebase后台消息推送数据传递至前端组件方案
当页面处于后台(失焦、最小化或浏览器未激活)时,Firebase的推送消息只会触发Service Worker(SW)中的onBackgroundMessage事件,而前端组件的onMessage仅在页面活跃时生效。要实现将SW接收到的消息同步到前端组件展示,可通过Service Worker与客户端的消息通信API完成,具体步骤如下:
1. 修改Service Worker文件(public/firebase-messaging-sw.js)
在onBackgroundMessage中,先将消息数据发送给所有打开的前端客户端,再处理系统通知:
const messaging = firebase.messaging(); messaging.onBackgroundMessage((payload) => { console.log('[firebase-messaging-sw.js] Received background message ', payload); // 推送消息至所有活跃的前端窗口 self.clients.matchAll({ includeUncontrolled: true, type: 'window' }) .then(clients => { if (clients.length > 0) { clients.forEach(client => { client.postMessage({ type: 'FIREBASE_BACKGROUND_MESSAGE', payload: payload }); }); } }); // 自定义系统通知内容(可选,按需调整) const notificationTitle = payload.notification?.title || '新通知'; const notificationOptions = { body: payload.notification?.body || '', icon: payload.notification?.icon || '/firebase-logo.png', // 可选:将消息数据附加到通知中,便于点击时使用 data: { payload: payload } }; return self.registration.showNotification(notificationTitle, notificationOptions); }); // 可选:监听通知点击事件,唤醒页面并传递数据 self.addEventListener('notificationclick', (event) => { event.notification.close(); // 打开应用主页(可替换为指定路由) event.waitUntil( self.clients.openWindow('/') .then(client => { if (client) { client.postMessage({ type: 'FIREBASE_NOTIFICATION_CLICK', payload: event.notification.data.payload }); } }) ); });
2. 改造前端Notification组件
在组件中监听来自Service Worker的消息事件,同时保留前台消息的监听逻辑:
import { useEffect, useState } from 'react'; import { getMessaging } from "firebase/messaging"; const NotificationComponent = () => { const messaging = getMessaging(); const [notifications, setNotifications] = useState([]); useEffect(() => { // 处理来自Service Worker的消息 const handleSWMessage = (event) => { switch (event.data.type) { case 'FIREBASE_BACKGROUND_MESSAGE': // 后台消息同步到组件状态,用于展示 setNotifications(prev => [...prev, event.data.payload]); console.log('收到后台消息:', event.data.payload); break; case 'FIREBASE_NOTIFICATION_CLICK': // 处理通知点击后的逻辑,比如跳转、高亮对应内容 console.log('通知被点击,数据:', event.data.payload); break; default: break; } }; // 注册Service Worker消息监听 navigator.serviceWorker.addEventListener('message', handleSWMessage); // 前台消息监听(页面活跃时触发) const unsubscribe = messaging?.onMessage((payload) => { setNotifications(prev => [...prev, payload]); console.log('收到前台消息:', payload); }); // 组件卸载时清理监听 return () => { navigator.serviceWorker.removeEventListener('message', handleSWMessage); unsubscribe?.(); }; }, [messaging]); return ( <div className="notification-container"> <h3>消息通知</h3> {notifications.map((item, index) => ( <div key={index} className="notification-item"> <h4>{item.notification?.title || '系统通知'}</h4> <p>{item.notification?.body || '无内容'}</p> </div> ))} </div> ); }; export default NotificationComponent;
注意事项
- 确保React项目已正确注册Service Worker,通常在
src/index.js中添加注册逻辑:if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/firebase-messaging-sw.js') .then(registration => console.log('SW registered:', registration)) .catch(err => console.log('SW registration failed:', err)); } - 浏览器需支持Service Worker和Push API(HTTPS环境或localhost下可正常测试)
- 若消息携带自定义数据,可从
payload.data中获取,而非payload.notification(后者仅包含系统通知相关字段)
内容的提问来源于stack exchange,提问作者John Anwar
相关产品推荐
相关产品推荐

