Socket.io server emitting an empty array to the client
In the input box of my app, I type a message and expect the message to be transmitted to the server and then transmitted back to the client so as to map the information to my UI.
While transmitting to the server seems to be working correctly, getting back the information from the socket.io server does not seem to work and returns an empty array.
Now the thing is when I input a message the first time, the server returns an empty array but when I input another message, the server now returns an array with one object instead of two. Also, the object it returns is the first message I typed initially and not the new one.
To sum everything up, server returns one object lesser than what it was given and what it returns is what it was given initially and not the new information.
This is the server console at the first instant which appears to work correctly
Here is the client console at the second instant which returns what was passed in the first instance
This is the server console at the second instant which also appear to work correctly
Here is the client code:
'use client'
import { io } from 'socket.io-client'
import { useEffect, useState } from 'react'
import { ChatSenderBox } from './ChatBox'
import { ChatRecieverBox } from './ChatBox'
import MessageInput from './MessageInput'
const ChatContainer = ({username, userImage}) => {
const [socket, setSocket] = useState(undefined)
const [allInfo, setAllInfo] = useState([])
// sending all info to the socket
const sendChatToServer = (chat) => {
socket.emit('chat', chat)
}
//getting back the emitted message
useEffect(()=>{
const socket = io('http://localhost:3001')
socket.on('chat', (chatRecieved) => {
setAllInfo(chatRecieved)
})
setSocket(socket)
}, [])
// This is a function passed as prop to the messageInput component
const addMessage = (chat) => {
const newChat = {...chat, username, userImage}
if(newChat.message !== ''){
setAllInfo([...allInfo, newChat])
sendChatToServer([...allInfo, newChat])
console.log(allInfo)
}
}
const ChatsArrangment = () => {
return allInfo.map((info, index) => {
if(info.username === username) return
<ChatSenderBox
key={index}
username={info.username}
profilePic={info.userImage}
message={info.message}
/>
return
<ChatRecieverBox
key={index}
username={info.username}
profilePic={info.userImage}
message={info.message}
/>
})
}
return (
<div className=' w-full h-full p-4 chatPage'>
<ChatsArrangment />
<MessageInput addMessage={addMessage}/>
</div>
)
}
export default ChatContainer
And this is the server code:
const express = require("express")
const http = require("http")
const { Server } = require("socket.io");
const app = express()
const server = http.createServer(app)
const io = new Server(server, {
cors:{
origin: 'http://localhost:3000',
methods: ["GET", "POST"]
}
})
io.on("connection", (socket) => {
console.log("A user is connected")
// messaged recieved and sent back to the client.
socket.on("chat", (chat)=>{
if(chat.lenght){
io.emit("chat", chat)
}
console.log(chat)
})
socket.on("disconnect", ()=>{
console.log("A user disconnected")
})
})
server.listen(3001, () => console.log('listening to port 3001'))
Answer
Actually your code works fine, the problem is in the placement of console
In react setState here (setAllInfo
) function is asynchronous, so the state changes won't be applied immediately. That's why the console
after setState still in old value.
Solution
Simply try to console outside of setState
or use useEffect
and add the value as dependency
useEffect(() => {
console.log(allInfo); // Updated value here
}, [allInfo]);
Also there is an issue in your react component, you have to use either inline js or pass allinfo
as a prop like below.
Inline condition
return ( <div className=" w-full h-full p-4 chatPage"> {allInfo.length && allInfo.map((info, index) => ( <ChatSenderBox key={index} username={info.username} profilePic={info.userImage} message={info.message} /> ))} <MessageInput addMessage={addMessage} /> </div> );
Or pass
allinfo
as prop the componentChatsArrangment
so it can render whenever theallinfo
changes.const ChatsArrangment = (data) => { return data.map((info, index) => ( <ChatSenderBox key={index} username={info.username} profilePic={info.userImage} message={info.message} /> )); }; return ( <div className=" w-full h-full p-4 chatPage"> {allinfo.length && <ChatsArrangment data={allinfo} />} <MessageInput addMessage={addMessage} /> </div> );