FCM - messaging().onMessage 重复回调 - 不使用 useEffect 卸载
FCM - messaging().onMessage duplicate callbacks - does not unmount with useEffect
我正在使用 FCM 将消息发送到 Android 应用程序,然后应用程序将消息呈现到 FlatList 组件中。当我收到新的 FCM 消息时,我想刷新 FlatList 组件,以便在列表中显示最新消息。我正在使用 useEffect 通过 setRefreshPage() 触发刷新。
下面的代码工作得很好,除了每次收到 FCM 消息并触发 useEffect 时,它似乎会创建第二个前台侦听器,这会导致后续消息的重复通知。我不认为 unsubscribeOnMessage();正在删除 useEffect 中现有的前台侦听器。
回调每次都加倍,即在收到第一个消息时有 1 个 FCM 消息回调,然后是下一个消息的 2 个回调,下一个消息的 4 个回调,等等。这让我想到了额外的 messaging().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: {...}
由于这 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 依赖项。
我正在使用 FCM 将消息发送到 Android 应用程序,然后应用程序将消息呈现到 FlatList 组件中。当我收到新的 FCM 消息时,我想刷新 FlatList 组件,以便在列表中显示最新消息。我正在使用 useEffect 通过 setRefreshPage() 触发刷新。
下面的代码工作得很好,除了每次收到 FCM 消息并触发 useEffect 时,它似乎会创建第二个前台侦听器,这会导致后续消息的重复通知。我不认为 unsubscribeOnMessage();正在删除 useEffect 中现有的前台侦听器。
回调每次都加倍,即在收到第一个消息时有 1 个 FCM 消息回调,然后是下一个消息的 2 个回调,下一个消息的 4 个回调,等等。这让我想到了额外的 messaging().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: {...}
由于这 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 依赖项。