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

React Native中firebase/messaging的onMessage无法访问Context Provider问题

解决FCM onMessage无法访问最新Context状态的问题

核心问题出在闭包捕获值的时效性和useEffect依赖缺失:你的useEffect依赖是空数组,currentPage只会在组件挂载时被读取一次,后续页面切换导致currentPage更新时,useEffect不会重新执行,onMessage的回调始终捕获的是初始的空值。

方案1:将currentPage加入useEffect依赖,重新订阅onMessage

每次currentPage更新时,取消旧的订阅并重新创建新的onMessage回调,确保回调能拿到最新的currentPage:

useEffect(() => {
  const { currentPage } = useContext(DataContext);
  console.log('current page on HomeScreen', currentPage);

  let unsubscribe;

  if (!isExpoGo) {
    // 权限获取、token发送等原有代码保持不变
    if (requestUserPermission()) {
      messaging().getToken().then((token) => {
        sendPushToken(token, user);
      });
    } else {
      console.log('Messaging: failed token status');
    }

    messaging().onNotificationOpenedApp((remoteMessage) => {
      console.log('Notification caused app to open from background state:', remoteMessage.notification);
      console.log('App should navigate : ', remoteMessage.data);
    });

    messaging()
      .getInitialNotification()
      .then((remoteMessage) => {
        if (remoteMessage) {
          console.log('Notification caused app to open from quit state:', remoteMessage.notification);
          console.log('App woke up : ', remoteMessage.data);
        }
      });

    // 订阅FCM前台消息,每次currentPage更新时重新订阅
    unsubscribe = messaging().onMessage((remoteMessage) => {
      console.log('current Page FCM :', currentPage);
      // 根据currentPage判断是否显示通知
      if (currentPage !== `${remoteMessage.data.type}/${remoteMessage.data.conversationId}`) {
        // 调用Notifee展示Toast/通知
      }
    });
  }

  // 组件卸载或currentPage更新时取消订阅
  return () => {
    if (unsubscribe) unsubscribe();
  };
}, [currentPage]); // 加入currentPage作为依赖

方案2:用useRef保存最新的currentPage(避免频繁重新订阅)

如果不想每次currentPage变化都重新订阅FCM,可以用useRef存储最新的状态,让闭包能访问到实时值:

const { currentPage } = useContext(DataContext);
const currentPageRef = useRef(currentPage);

// 监听currentPage变化,同步更新ref
useEffect(() => {
  currentPageRef.current = currentPage;
}, [currentPage]);

useEffect(() => {
  if (!isExpoGo) {
    // 权限、token等代码保持不变
    if (requestUserPermission()) {
      messaging().getToken().then((token) => {
        sendPushToken(token, user);
      });
    } else {
      console.log('Messaging: failed token status');
    }

    messaging().onNotificationOpenedApp((remoteMessage) => {
      console.log('Notification caused app to open from background state:', remoteMessage.notification);
      console.log('App should navigate : ', remoteMessage.data);
    });

    messaging()
      .getInitialNotification()
      .then((remoteMessage) => {
        if (remoteMessage) {
          console.log('Notification caused app to open from quit state:', remoteMessage.notification);
          console.log('App woke up : ', remoteMessage.data);
        }
      });

    const unsubscribe = messaging().onMessage((remoteMessage) => {
      // 直接访问ref.current获取最新的currentPage
      const latestPage = currentPageRef.current;
      console.log('current Page FCM :', latestPage);
      if (latestPage !== `${remoteMessage.data.type}/${remoteMessage.data.conversationId}`) {
        // 展示通知逻辑
      }
    });

    return unsubscribe;
  }
}, []); // 依赖保持空数组,只订阅一次

额外注意事项

  • 确保DataContext.Provider包裹了当前组件的上层组件(比如App根组件),否则useContext会返回默认空值。
  • FCM的onMessage仅在应用处于前台时触发,后台/杀死状态的通知需通过onNotificationOpenedApp或getInitialNotification处理。

内容的提问来源于stack exchange,提问作者Yann Verdier

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 18:43:26