When I'm emitting message
from client side.
I'm receiving lot of same duplicated message
on server side or in my message displaying container div
here is the code
Global Socket Provider Context
A simple context which provide socket to all children or components
// fileName : SocketProvider.js
import { createContext } from "react";
import { io } from "socket.io-client";
const socket = io("http://localhost:8080/", { withCredentials: true });
const SocketContext = createContext();
export const SocketProvider = ({ children }) => {
return (
<SocketContext.Provider value={{ socket }}>
{children}
</SocketContext.Provider>
);
};
export default SocketContext;
And I've wrapped SocketProvider
in App.js like this
<SocketProvider>
<Main/>
</SocketProvider>
In Dashboard Page or Main Page
Where I've div for displaying messages and input message box whenever user press enter or click send button which is img
I'm emitting a message here is the code
// filename : Main.jsx
// all things imported correctly
import ...
const Main = ()=> {
const { socket } = useContext(SocketContext);
const [message, setMessage] = useState("");
const [conversation, setConversation] = useState([]);
// another global context
const { currentUserId } = useContext(UserContext);
const { selectedUserId, setSelectedUserId } = useContext(SelectedUserContext);
// code for changing selectedUserId
// ...
...
.... //
// on start sending userJoined
useEffect(() => {
socket.emit("userJoined", {
senderUserId: currentUserId,
receiverUserId: selectedUserId,
});
}, [socket, currentUserId, selectedUserId]);
// useEffect for listening messages
useEffect(() => {
const onMessageReceived = (msg) => {
setConversation((conversations) => [...conversations, msg]);
};
socket.on("message", onMessageReceived);
return () => {
socket.off("message", onMessageReceived);
};
}, [socket]);
// this function will send message
const sendMessage = useCallback(() => {
if (!message) return;
socket.emit("message", {
msg: message,
sentBy: "Unknown"
});
setMessage("");
}, [socket, message]);
// on enter btn pressed
useEffect(() => {
const handleEnterKeyPressed = (e) => {
if (e.keyCode === 13 && e.shiftKey === false && e.ctrlKey === false)
sendMessage();
};
element.addEventListener("keydown", handleEnterKeyPressed);
return () => {
element.removeEventListener("keydown", handleEnterKeyPressed);
};
}, [sendMessage]);
return (
<div className="container">
<div className="msgContainer">
{conversation.map((data)=>((
<h1 className="...">{data.msg}</h1>
<p className="...">{data.sentBy}</p>
)}
</div>
<input
value={message}
onChange={(e)=>setMessage(e.target.value)}
placeholder="Enter message here"/>
<img className="..." src={sendIcon} onClick={sendMessage}>
</div>
);
}
export default Main;
Code In Server Side Where I'm Listening for message
//filename: server.js
io.on("connection", (socket) => {
socket.on("userJoined", (userJoinedData) => {
const chatRoomId = generateChatRoomId(userJoinedData);
socket.on("message", async (msgData) => {
// this console log many times or more than 11
console.log(`DEBUG: New Message Arrived :`, msgData);
// saving msg to mongo db
const savedMessage = await saveMsg(msgData);
io.to(chatRoomId).emit("message", savedMessage);
});
});
});
and even I got following warning in terminal :
(node:14040) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message listeners added to [Socket]. Use emitter.setMaxListeners() to increase limit
Any help will be always appreciated :)
CodePudding user response:
As @NickParsons mentioned -
Is that peice of code being executed multiple times?
Whenever currentUserId
or selectedUserId
changes you are emiting userJoined
in server code. And userJoined
listener on server side get called and your message listener listen again your data so that's why you are getting duplicated data.
To fix this you have to place message
listener outside of userJoined
listener!
I know you are getting some info of
userJoinedData
so that's why you have placemessage
listener insideuserJoined
.
So you have to also pass that userJoinedData while emitting message in your client side and change code in your server side like this -
//filename: server.js
io.on("connection", (socket) => {
socket.on("userJoined", (userJoinedData) => {
const chatRoomId = generateChatRoomId(userJoinedData);
// .. your other codes
});
// but place message listener outside here
socket.on("message", async (msgData, userJoinedData) => {
// now here also you can generate chatRoomId
const chatRoomId = generateChatRoomId(userJoinedData);
// saving msg to mongo db
const savedMessage = await saveMsg(msgData);
io.to(chatRoomId).emit("message", savedMessage);
});
});