You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 16:10:25