title: FCM - messaging().onMessage duplicate callbacks - does not unmount with useEffect
body: <p>I'm using FCM to send messages to an Android app which then renders the messages into a FlatList component. When I new FCM message is received I want to refresh the FlatList component so the latest message is displayed in the list. I'm using useEffect to trigger the refresh with setRefreshPage().</p>
  <p>The code below works great, except that every time an FCM message is received and the useEffect fires it appears to create a second foreground listener which results in duplicate notifications of subsequent messages. I don't think the unsubscribeOnMessage(); is removing the existing foreground listener in useEffect.</p>
  <p>The callbacks double each time, i.e. 1 FCM message callback on the first message receipt, then 2 callbacks for the next message, 4 callbacks for the next, etc. Which makes me think extra messaging().onMessage foreground listeners are being created on each useEffect trigger.</p>
  <p>What's the right way of removing the messaging listener when the useEffect is fired?</p>
  <p>I've only tested this code on Android so far.</p>
  <pre><code>function HomeScreen() {
  
  const [data, setData] = useState([]);
  const [refreshPage, setRefreshPage] = useState(false);
  
  useEffect(async () =&gt; {
  
    const value = await AsyncStorage.getItem('storedMessages');
  
    // ...functions to retrieve and sort historical messages into array &quot;sortedInput&quot;
  
    setData(sortedInput);  // setState to provide initial data for FlatList component
  
    };
  
    const unsubscribeOnMessage = messaging().onMessage(async remoteMessage =&gt; {
  
      console.log(&quot;DEBUG: Received FCM message: &quot; + JSON.stringify(remoteMessage));
  
      // Function to process new message and insert into local storage
      await _handleNewMessage(remoteMessage);
  
      // Display notification to user
      await onDisplayNotification(remoteMessage);
  
      // Trigger refresh of FlatList component with setState
      setRefreshPage(Math.random() * 100);
  
    });
  
    return () =&gt; {
      unsubscribeOnMessage();
    };
  
  }, [refreshPage]);
  
  
  // Render messages into FlatList view
  function renderMessagesFlatList(data) {
  
    if (isLoading) {
  
      return (
        &lt;ActivityIndicator
          size=&quot;large&quot;
          color=&quot;#0000ff&quot;
          /&gt;
      );
  
    } else if (data.length === 0) {
  
      return (
      &lt;Text&gt;No notifications to display&lt;/Text&gt;
      );
  
      } else {
  
    return (
    &lt;FlatList
        data={data}
        keyExtractor={(item, index) =&gt; item.id}
        renderItem={({ item }) =&gt; (
            &lt;&gt;
            &lt;View style={{ flexDirection: 'row', flex: 1 }}&gt;
            &lt;Image
              style={{ width: 40, height: 40 }}
              source={{uri:item.icon}}
            /&gt;
              &lt;View style={{ flex: 1, paddingLeft: 5 }}&gt;
              &lt;Text style={{ color: '#000000', fontWeight: 'bold' }}&gt;{item.sender}&lt;/Text&gt;
              &lt;Text&gt;{timeSince(item.time)}&lt;/Text&gt;
              &lt;/View&gt;
            &lt;/View&gt;
            &lt;Text style={{ paddingTop: 4 }}&gt;{item.body}&lt;/Text&gt;
            &lt;Divider style={{ backgroundColor: '#e7e5e5', height: 2, marginTop: 5, marginBottom: 5 }} /&gt;
            &lt;/&gt;
          )}
      /&gt;
    );
  
    }
  };
  
  
    return (
        &lt;View style={{ margin: 5 }} &gt;
        {console.log(&quot;DEBUG: isLoading = &quot; + isLoading)}
        {console.log(&quot;DEBUG: data = &quot; + JSON.stringify(data))}
  
        {renderMessagesFlatList(data)}
  
        &lt;/View&gt;
    );
  
  };
  
  </code></pre>
  <p>Here is what I end up seeing in the logfiles when I send one FCM message per minute:</p>
  <pre><code>04-22 08:40:00.000 ReactNativeJS: DEBUG: Received FCM message: {...}
  
  04-22 08:41:00.000 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:41:00.006 ReactNativeJS: DEBUG: Received FCM message: {...}
  
  04-22 08:42:00.000 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:42:00.004 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:42:00.009 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:42:00.014 ReactNativeJS: DEBUG: Received FCM message: {...}
  
  04-22 08:43:00.000 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:43:00.006 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:43:00.011 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:43:00.017 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:43:00.021 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:43:00.028 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:43:00.036 ReactNativeJS: DEBUG: Received FCM message: {...}
  04-22 08:43:00.049 ReactNativeJS: DEBUG: Received FCM message: {...}
  </code></pre>