FCM - messages().onMessage 重复回调 - 不使用 useEffect

时间:2021-04-22 07:45:04

标签: react-native react-native-firebase

我正在使用 FCM 将消息发送到 Android 应用程序,然后该应用程序将消息呈现到 FlatList 组件中。当我收到新的 FCM 消息时,我想刷新 FlatList 组件,以便在列表中显示最新的消息。我正在使用 useEffect 通过 setRefreshPage() 触发刷新。

下面的代码效果很好,除了每次收到 FCM 消息并且 useEffect 触发时,它似乎创建了第二个前台侦听器,从而导致后续消息的重复通知。我不认为 unsubscribeOnMessage();正在删除 useEffect 中现有的前台侦听器。

每次回调都会加倍,即第一条消息收到 1 个 FCM 消息回调,下一条消息有 2 条回调,下一条消息有 4 条回调,等等。这让我觉得正在使用额外的消息 ().onMessage 前台侦听器在每个 useEffect 触发器上创建。

当 useEffect 被触发时删除消息监听器的正确方法是什么?

到目前为止,我只在 Android 上测试过这段代码。

function HomeScreen() {

const [data, setData] = useState([]);
const [refreshPage, setRefreshPage] = useState(false);

useEffect(async () => {

  const value = await AsyncStorage.getItem('storedMessages');

  // ...functions to retrieve and sort historical messages into array "sortedInput"

  setData(sortedInput);  // setState to provide initial data for FlatList component

  };

  const unsubscribeOnMessage = messaging().onMessage(async remoteMessage => {

    console.log("DEBUG: Received FCM message: " + 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 () => {
    unsubscribeOnMessage();
  };

}, [refreshPage]);


// Render messages into FlatList view
function renderMessagesFlatList(data) {

  if (isLoading) {

    return (
      <ActivityIndicator
        size="large"
        color="#0000ff"
        />
    );

  } else if (data.length === 0) {

    return (
    <Text>No notifications to display</Text>
    );

    } else {

  return (
  <FlatList
      data={data}
      keyExtractor={(item, index) => item.id}
      renderItem={({ item }) => (
          <>
          <View style={{ flexDirection: 'row', flex: 1 }}>
          <Image
            style={{ width: 40, height: 40 }}
            source={{uri:item.icon}}
          />
            <View style={{ flex: 1, paddingLeft: 5 }}>
            <Text style={{ color: '#000000', fontWeight: 'bold' }}>{item.sender}</Text>
            <Text>{timeSince(item.time)}</Text>
            </View>
          </View>
          <Text style={{ paddingTop: 4 }}>{item.body}</Text>
          <Divider style={{ backgroundColor: '#e7e5e5', height: 2, marginTop: 5, marginBottom: 5 }} />
          </>
        )}
    />
  );

  }
};


  return (
      <View style={{ margin: 5 }} >
      {console.log("DEBUG: isLoading = " + isLoading)}
      {console.log("DEBUG: data = " + JSON.stringify(data))}

      {renderMessagesFlatList(data)}

      </View>
  );

};

这是我每分钟发送一条 FCM 消息时最终在日志文件中看到的内容:

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: {...}

1 个答案:

答案 0 :(得分:0)

由于这 2 行,您会收到 FCM 重复更新,从而导致循环,这是一种反模式。

setRefreshPage(Math.random() * 100);  //<-- You are updating the state refreshPage


}, [refreshPage]); // <--- You use refreshPage as a dependency means useEffect will be called. And then you will setRefreshPage again

除此之外,我无法给您提供更多建议,因为我不确定您为什么设置了 setRefreshPage。如果您希望它在页面加载时仅触发一次,则删除 refreshPage 依赖项。

相关问题