I have signalR chat hub on the ASP.NET Core API, and I use @microsoft/signalr package in react, to connect websocket and invoke functions on the server. I have few handlers that handle messages sent from server. One of them is this:
useEffect(() => {
if (!connection) return
connection.on("ReceiveMessage", (user, message) => {
if (
(message.fromUserId === authUserId &&
message.toUserId === chattingUser?.id) ||
(message.fromUserId === chattingUser?.id &&
message.toUserId === authUserId)
) {
const newMessages = [...chattingUser.messages]
newMessages.push(message)
setChattingUser((prevUser) => {
return { ...prevUser, messages: newMessages }
})
}
})
}, [authUserId, chattingUser, connection])
This handler needs to change whenever something from dependencies is changed. When this useEffect runs, a new handler is created and handler(s) that are created before are NOT removed. This makes a lot of subscriptions to the same event, and when ReceiveMessage happens, all of previous handlers are executed. I couldn't find a solution to unsubscribe (remove) all previous handlers using @microsoft/signalr npm package.
Try:
useEffect(() => {
if (!connection) return
// I added this line.
connection.off("ReceiveMessage");
connection.on("ReceiveMessage", (user, message) => {
if (
(message.fromUserId === authUserId &&
message.toUserId === chattingUser?.id) ||
(message.fromUserId === chattingUser?.id &&
message.toUserId === authUserId)
) {
const newMessages = [...chattingUser.messages]
newMessages.push(message)
setChattingUser((prevUser) => {
return { ...prevUser, messages: newMessages }
})
}
})
}, [authUserId, chattingUser, connection])
Basically, the point is, that there should be an off method, which can be used to unsubscribe.