I'm trying to create a realtime online chat using React, node and mongodb. In my opinion, the chat shoudl work this way: client send the object of the message he created to the server to save it via rest(works properly) and via socket so the socketserver "broadcast" the message to every socket that is in the same room(socket on connection is put in a room according to something store in localstorage). So, other client in the same room should then recive the message, and happend it to the chat. But it is not workink. In fact, the following error shows up: Uncaught TypeError: msg.map is not a function
This is my react code:
import {useState, useEffect} from 'react';
import axios from 'axios';
import { io } from "socket.io-client";
const Chat = () => {
const [msg, setMsg] = useState([]);
const [message, setMessage] = useState('');
const socket = io("http://localhost:5050");
useEffect(() => {
if(v.group.name){
axios.get(`http://localhost:5050/chat/getmsg/${v.group.name}`)
.then(group => {
setMsg(group.data)
})
}
}, [v.group.name])
useEffect(() => {
if(localStorage.getItem('isG') === '1'){
socket.on("connect", () => {
socket.emit("groupName", {id:localStorage.getItem('gruop')})
})
socket.on("message", messageS => {
if(messageS.sender !== localStorage.getItem('user'))
setMsg(...msg, messageS)
})
}
// eslint-disable-next-line
}, [socket])
const sendMSG = (e) => {
e.preventDefault();
if(message !== ""){
axios.post("http://localhost:5050/chat/sendmsg", {name:v.group.name, sender:localStorage.getItem('user'), text:message})
.then(() => {
setMessage('');
socket.emit("message", {name:v.group.name, sender:localStorage.getItem('user'), text:message})
setMsg(...msg, {name:v.group.name, sender:localStorage.getItem('user'), text:message})
});
}
}
return <div className="containerLogin1">
<div>
<h3>Chat Name</h3>
</div>
<div className="chatSpace">
{
msg.map((m) => {
return <p key={m._id}>{m.text}</p>
})
}
</div>
<form className="sMSG">
<input type="input" style={{'border':'2px solid black'}} value={message} onChange={(e) => setMessage(e.target.value)}/>
<button className="buttSend" onClick={sendMSG} spellCheck="false">Send</button>
</form>
</div>
}
And this is server code, but I think that he is working fine:
....
const httpServer = app.listen(port, () => {console.log(`Server listening on port ${port}`)});
const { Server } = require("socket.io");
const io = new Server(httpServer, {
cors : {
origin: "*",
methods:["GET", "POST"]
}
} );
io.on("connection", (socket) => {
let currentRoom = "";
socket.on("groupName", msg => {
socket.join(msg.id "")
currentRoom = msg.id
})
socket.on("text-change", newText => {
io.to(currentRoom).emit( "text-change", {text:newText, emitter:socket.id})
})
socket.on("message", message => {
io.to(currentRoom).emit("message", message);
})
})
I tryied with a bounch of console.log to see where the error could be, but I couldn't find out. It seems that somewhere in the code, msg turns from an array to an object, and so map function crashes. Can someone please help me? Thanks
CodePudding user response:
You have these 2 lines in your code where you are trying to copy the last array and add new object to it:
setMsg(...msg, messageS);
And:
setMsg(...msg, {name:v.group.name, sender:localStorage.getItem('user'), text:message});
These parts are the problem, you should add [] around them. So:
setMsg([...msg, messageS]);
setMsg([...msg, {name:v.group.name, sender:localStorage.getItem('user'), text:message}]);