Skip to content
Advertisement

Why does the sender message only appear when the recipient sends a message? (socketio) (nodejs) (reactjs)

I am developing a realtime chat in nodejs and react and socket io. In theory the chat is working, but the problem is that the sender’s message only appears on the screen when the recipient sends a message too.

ex : I have browser 1 and browser 2. Every time browser 1 sends messages, these messages appear on its screen, but these messages only appear for browser 2 when browser 2 sends a message.

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 = []

io.on('connection', (socket) => {
    socket.on('send-message', (data) => {
        messages.push(data);
        socket.emit('message-from-server', messages);
        console.log(messages); 
    })
});

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;

react/socketio

import * as C from './styles';

import { io } from 'socket.io-client';
import { useNavigate } from 'react-router-dom';
import { useEffect, useState } from 'react';

const Chat = () => {
  const navigate = useNavigate();

  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) => {
        setChatMessages(data); 
      })
    }
  }, [socket])

  const handleSendMessage = () => {
    if (message) {
      socket.emit('send-message', { message });
      setMessage('');  
    }
  }

  const handleExitChat = () => {
    navigate('/');
  }

  return (
    <C.Container>
        <C.MessagesChat>
          <h2>Messages</h2>
        </C.MessagesChat>
        {chatMessages.map(text => {
          return (
            <C.Messages>
              <p>{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.Container>
  )
}

export default Chat;

Advertisement

Answer

You’re using

socket.emit('message-from-server', messages);

Try using io.emit instead, which broadcasts to all attached sockets. Socket.emit is used to send a message only to the called socket. In this case, that means the socket that first sent the message. This can be helpful for if you just want to notify that individual socket that something processed correctly, etc., but it isn’t useful for when you want to notify other users of a socket’s actitivies.

EDIT: Here’s a link to the docs that describe your various emit options: https://socket.io/docs/v4/broadcasting-events/

Here’s what your server-side code should look like:

io.on('connection', (socket) => {
    // Define our routes first, but note the key new emit below this listener
    socket.on('send-message', (data) => {
        messages.push(data);
        // Notify all connected users each time a message is posted
        io.emit('message-from-server', messages);
        console.log(messages);
    }

    // THIS IS NEW
    // This is your initial load, to get the messages when you open the page.
    socket.emit('message-from-server', messages);

}

Note the difference between the io.emit that I use in the listener and the socket.emit that I use when first connecting.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement