'Socket.io/React Chat App - Connection established

i have two components: where I set the username and room and then I have the component where is the send message and displays the conversation.

When I login on the component, I navigate to the component and trigger the connection with the socket:

const handleClick = (e) => {
    e.preventDefault();
    navigate("/chatroom", { state: { username, room } });
  };

I have two issues regarding the connection with the socket:

-I´ve tried to start the connection inside an useEffect():

export default function ChatRoom() {
  const [chatMessage, setChatMessage] = useState("");
  const [showmsg, setShowMsg] = useState([]);
  const [showObj, setShowObj] = useState([]);
  const [submited, setSubmited] = useState(false);


const handleSubmit = (e) => {
    e.preventDefault();

    setShowMsg((oldmsg) => [...oldmsg, chatMessage]);
    setChatMessage("");
    setSubmited(true);
  };

  const { state } = useLocation(); //to get data from <Home/> component
    useEffect(() => {
    const socket = io("http://localhost:3000");
    //Message from server
    socket.on("message", (msg) => {
      setShowObj((oldmsg) => [...oldmsg, msg]);
      setSubmited(false);
      console.log(showObj);
    });

    //Message to server
    socket.emit("chatMessage", {
      user: state.username,
      text: showmsg[showmsg.length - 1],
    }); //pass the last msg
  }, [submited]);

ServerSide:

io.on("connection", (socket) => {
  //Welcome current user
  socket.emit("message", formatMessage("MiouriChat", "Welcome to the chat!"));

  //Broadcast when user connects
  socket.broadcast.emit(
    "message",
    formatMessage("MiouriChat", "A user has joined the chat")
  );

  //Run when clients disconects
  socket.on("disconnect", () => {
    io.emit("message", formatMessage("MiouriChat", "A user has left the chat"));
  });

  //Listen to chat message from client
  socket.on("chatMessage", (msg) => {
    io.emit("message", formatMessage(msg.user, msg.text));
  });
});

This way, everytime I submit a msg ([submited] change), the connection is reseted for obvious reason and get the "welcome" messages everytime it reconects.

If I put the connection outside the useEffect(), the connection reseted everytyme I type a letter on the message input (becouse the state updates.)

What is the best solution for this?



Solution 1:[1]

For your initial "welcome" message, you want a useEffect that only runs after the first render of the page as explained in the docs - by specifying an empty dependency array. This is also a really nice place to define the "cleanup" function, where you want to send a "disconnect" message to your server (in fact the cleanup docs even use a chat API as an example!):

useEffect(() => {
    const socket = io("http://localhost:3000");
    //Message from server
    socket.on("message", (msg) => {
      setShowObj((oldmsg) => [...oldmsg, msg]);
      console.log(showObj);
    });

    return () => {
        socket.emit("disconnect"); // cleanly disconnect from server
    };
}, []); // <- Empty dependency array === only runs after initial render

That solves the "welcome message" and "disconnect" problems, and you no longer need the submited state variable. I can't really help you with the rest, but again I commend the useEffect documentation to you, particularly the example which is so applicable to your use case!

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 millhouse