'Why React Component render many time when get event from socket.io?

I am using socket.io for my project social network web, when user connect I join, but when I get message from socket.io by group chat, My component render message many time. Example: My group has 4 people, I send message to group then one user get message 3 times, I tried many time but not working, Here is my code: socket.ts:

import io from 'socket.io-client';
export const socket = io('http://localhost:8800');

App.ts:

useEffect(() => {
    if (user) {
      socket.emit('setup', user);
    }
  }, [user]);

ChatBox.tsx:

useEffect(() => {
    socket.emit('join chat', conversationId);
  }, [conversationId]);

  useEffect(() => {
    socket.on('typing', () => setIsTyping(true));
    socket.on('stop typing', () => setIsTyping(false));
  }, []);

  useEffect(() => {
    socket.on('getMessage', (data: { message: messageType; conversation: conversationType }) => {
      console.log(data);
      setMessages((prev) => [data.message, ...prev]);
    });
  }, []);

  useEffect(() => {
    const getMessages = async () => {
      setIsFetchingMessage(true);
      if (conversationId) {
        const res = await getMessagesApi(conversationId);
        setMessages(res);
      }
      setIsFetchingMessage(false);
    };
    getMessages();
  }, [conversationId]);

  const handleChangeMessageText = (e: React.ChangeEvent<HTMLInputElement>) => {
    setMessageContent(e.target.value);
    socket.emit('typing', conversationId);
    if (typingTimeout.current) {
      clearTimeout(typingTimeout.current);
    }
    typingTimeout.current = setTimeout(() => {
      socket?.emit('stop typing', conversationId);
    }, 2000);
  };

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (conversationId) {
      const res = await createMessageApi(conversationId, messageContent);
      if (res) {
        socket.emit('newMessage', { message: res, conversation: currentConversation });
        setMessages((prev) => [res, ...prev]);
        setConversations((prev) =>
          prev.map((c) => (c._id === conversationId ? { ...c, lastMessage: res } : c))
        );
      }
    }
    setMessageContent('');
  };

My code in backend:

io.on("connection", (socket) => {
  socket.on("setup", (userData) => {
    console.log("User connect: ", userData._id);
    addNewUser(userData, socket.id);
    socket.join(userData._id);
    socket.emit("onlineUsers", onlineUsers);
  });

  socket.on("join chat", (room) => {
    socket.join(room);
    console.log("User joined chat: ", room);
  });

  socket.on("newMessage", ({ message, conversation }) => {
    conversation.members.forEach((member) => {
      if (member._id == message.sender._id) return;
      const user = getUser(member._id);
      socket.in(conversation._id).emit("getMessage", { message, conversation });
    });
  });

Error: error image Anyone can help me. Thanks!!!



Solution 1:[1]

  socket.on("newMessage", ({ message, conversation }) => {
    conversation.members.forEach((member) => {
      if (member._id == message.sender._id) return;
      const user = getUser(member._id);
      socket.in(conversation._id).emit("getMessage", { message, conversation });
    });
  });

Change this to

  socket.on("newMessage", ({ message, conversation }) => {
      socket.in(conversation._id).emit("getMessage", { message, conversation });
     }
  });

You are emitting the message conversation.members.length times, you only need to emit it once.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1