Home > database >  How to prevent socketIO from emitting duplicate data in React Js
How to prevent socketIO from emitting duplicate data in React Js

Time:08-27

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 place message listener inside userJoined.

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);
    });

});

  • Related