I'm developing a real-time chat using socket, my main idea was to save the user's nickname in localStorage and take that nickname and send it to the server along with the message.
ReactJS
import * as C from './styles';
import { io } from 'socket.io-client';
import { useNavigate } from 'react-router-dom';
import { useContext, useEffect, useState } from 'react';
import AuthContext from '../../context/AuthContext';
const Chat = () => {
const navigate = useNavigate();
const { showMyName } = useContext(AuthContext);
const [name, setName] = useState('');
const [message, setMessage] = useState('');
const [chatMessages, setChatMessages] = useState([]);
const [socket, setSocket] = useState(null);
useEffect(() => {
setSocket(io("http://localhost:3010"));
}, []);
useEffect(() => {
if (socket) {
socket.on('message-from-server', (data, name) => {
setChatMessages(data);
console.log(name);
})
}
}, [socket])
const handleSendMessage = () => {
const nick = JSON.parse(localStorage.getItem("name"))[0];
setName(nick);
if (message) {
socket.emit('send-message', { message, name });
setMessage('');
}
}
const handleExitChat = () => {
navigate('/');
}
return (
<C.Container>
<C.MessagesChat>
<h2>Messages</h2>
</C.MessagesChat>
{chatMessages.map(text => {
return (
<C.Messages>
<p>{name}: {text.message}</p>
</C.Messages>
)
})}
<C.MessageText>
<textarea
name=""
id=""
cols="30"
rows="10"
placeholder='Digite sua mensagem...'
value={message}
onChange={(e) => setMessage(e.target.value)}
></textarea>
<button onClick={handleSendMessage}>Enviar</button>
</C.MessageText>
<C.Logout>
<button onClick={handleExitChat}>Abandonar a conversa</button>
<button onClick={handleExitChat}>Destruir a conversa</button>
</C.Logout>
</C.Container>
)
}
export default Chat;
ServerJs
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const dotenv = require('dotenv')
const app = express();
const mongoose = require('mongoose');
const http = require('http');
const server = http.createServer(app);
const { Server } = require('socket.io');
const io = new Server(server, {
cors: {
origin: ['http://localhost:3000'],
}
});
dotenv.config();
const nameRoutes = require('./routes/nameRoutes');
app.use(express.json());
app.use(cors());
app.use(bodyParser());
app.use('/name', nameRoutes);
app.use('/', (req, res) => {
res.status(200).json({ msg: 'API IS ALIVE!' });
})
let messages = []
let nick = ''
io.on('connection', (socket) => {
socket.on('send-message', (data, name) => {
messages.push(data);
nick = name;
io.emit('message-from-server', messages, nick);
},
socket.emit('message-from-server', messages, nick),
)
});
async function connection () {
const uri = process.env.MONGO_URI;
const port = process.env.PORT;
try {
await mongoose.connect(uri);
console.log('Connected to database');
server.listen(port, () => {
console.log(`Listening on port ${port}`)
});
} catch (err) {
console.log(err);
}
}
connection();
module.exports = app;
When I open a browser this works, but when I open the second browser with another name in localStorage, my messages from browser 1 that I sent end up becoming messages with the name of browser 2 on that screen. Does anyone know what the best way to fix isos would be?
CodePudding user response:
This is the same problem you were having with your other question. I really recommend you take some time to watch some socket.io tutorials and read the docs.
On your client you are sending socket.emit('send-message', { message, name });
.
That means on the server side you are receiving an event send-message
with data === { message, name }
.
socket.on('send-message', (data) => {
messages.push(data.message);
nick = data.name;
io.emit('message-from-server', messages, nick);
}
This is the way you would get it to do what you are expecting, but I really think you should read the docs so that you can get a grasp on these types of questions more easily.
Because at the end of this, with io.emit('message-from-server', messages, nick);
, you're emitting the entire string of messages again, not just the most recent one, and you're including the user's nickname. It probably isn't going to work--really you need to restructure everything to emit only the most recent message after initial load (but that's another question).