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
相关产品推荐
相关产品推荐

