0

I am trying to practice socket.io with React.js so I am trying to send messages between two clients, however I'm struggling with displaying the messages. I want to show the past messages sent. Now I was thinking about doing it as an array because a state didn't work. When console logging the array it shows up in the console but never renders out

import { useEffect, useState } from "react";
import io from "socket.io-client";
import "./App.css";

let socket;
const CONNECTION_PORT = "localhost:3001/";

function App() {
  const [loggedIn, setLoggedIn] = useState(false);
  const [room, setRoom] = useState("");
  const [userName, setUserName] = useState("");
  const [message, setMessage] = useState("");
  var itemArray = [];

  useEffect(() => {
    //connect to the socket
    socket = io(CONNECTION_PORT);

    socket.on("receive-message", (data) => {
      itemArray.push(data);
      console.log("Pong");
      console.log(itemArray);
    });

    //receiving messages
    socket.on("authentication", (bool) => {
      if (bool === true) {
        setLoggedIn(true);
      }
    });
  }, [CONNECTION_PORT]);

  //Sending a request to join the room
  const connectToRoom = () => {
    socket.emit("join-room", room, userName);
  };

  const sendMessage = () => {
    socket.emit("send-message", message);
  };

  return (
    <div className="App">
      {!loggedIn ? (
        <div className="login">
          <input
            type="text"
            placeholder="Name..."
            onChange={(e) => {
              setUserName(e.target.value);
            }}
          />
          <input
            type="text"
            placeholder="Room..."
            onChange={(e) => {
              setRoom(e.target.value);
            }}
          />
          <button onClick={connectToRoom}> Enter Chat</button>
        </div>
      ) : (
        <div>
          <input
            type="text"
            placeholder="Send Message..."
            onChange={(e) => {
              setMessage(e.target.value);
            }}
          />
          <button onClick={sendMessage}>Send Message</button>
          <div>
            {itemArray.map((data) => {
              console.log(data);
            })}
          </div>
        </div>
      )}
    </div>
  );
}
export default App;

2 Answers 2

1

The array is updating, but there is nothing to tell React to render the update. Any of these changes will cause the component to render again:

  1. Update to props
  2. Update to state
  3. Context value changes

React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.

You are updating an array variable within the component, but this won't trigger a render. Move the array into state:

const [messages, setMessages] = useState([]);
...
useEffect(() => {
    ...
    socket.on("receive-message", (data) => {
      // update the state which triggers a render
      setMessages(prevState => [...prevState, data]);
    });

}, [CONNECTION_PORT]);

Sign up to request clarification or add additional context in comments.

7 Comments

okay this works when A sends a message it sends it and B receives but if B sends a message back it refreshes it multiple times
What do you mean it refreshes it multiple times? This sounds like the message is being emitted multiple times–console.log to determine that.
doesn't matter I changed the console logs. Now the results of this code is that when A sends multiple messages, it displays it and the one last message of B, but as soon as B sends a message it clears out A's messages. However for receiving the messages it replaces the last one and doesn't stack unlike for the sender
OK, but we are now on to a different issue which is correctly emitting messages to those in a room. The issue is not about updating array in react and having it render. Both clients need to receive the message (receive-message) so they can update their relevant state.
how? from what I understand ...messages gets the last state of messages and adds the new data to the array? However in my case it doesn't get the last state on the received message it just adds it
|
0

You need to return data to see it Map returns each value you traverse so , you have to make sure say you want to see data like in a list Please make sure to return like this

Inside map function

{itemArray.map((data) => {
              return<li>{data.propertyName}</li>
            })}

Here property will be anything of an object property

3 Comments

the issue is that the component will not re-render if the itemArray variable is updated
Try using useEffect with second parameter as the updated array
Also an array is an object in JavaScript so changing it doesn't implies that the component will know that it's chnged , you need to use a flag and rsuch as reRender true false and use that as reference , this way it will see there was a chnage otherwise it won't affect in the prev one cause an object is still an object in JavaScript

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.