【问题标题】:message sent but not received socket.on(...) for client消息已发送但未接收到客户端的 socket.on(...)
【发布时间】:2021-10-09 22:17:52
【问题描述】:

(工作中)我可以看到消息已很好地发送到服务器:

// function used in reactjs(client)
const sendMessage = () => {
  const data = {
    room: room,
    content: {
      author: userName,
      message: message
    }
  }
  Promise.resolve(socket.emit('send_message', data))
  .then(() => setMessage(''));
}

useEffect(() => {
  socket.on('receive_message', data => {
    console.log(data);
  });
}, []);
// function used in index.js(server)
io.on('connection', (socket) => {
  console.log(socket.id);

  socket.on('join_room', (roomName) => {
    socket.join(roomName); // creates room with the name
    console.log('User Joined Room:', roomName);
  });

  socket.on('send_message', (data) => {
    console.log("data =", data);
    socket.to(data.room).emit('receive_message', data.content);
  });

  socket.on('disconnect', () => {
    console.log('USER DISCONNECTED')
  });
});

(问题)谁能告诉我为什么receive_message 没有出现在console.log 中?

  • 注意:它只会显示我是否执行了一些操作,例如在反应文件中添加一些注释并保存它。(奇怪)

两个文件的完整代码

index.js(服务器)

const express = require('express');
const morgan = require('morgan');
const { createServer } = require('http');
const { Server } = require('socket.io');
const cors = require('cors');

const app = express();
app.use(cors());
app.use(express.json());
app.use(morgan('dev'));
const httpServer = createServer(app);

const io = new Server(httpServer, {
  cors: true,
  origins: ['http://localhost:3000']
});

io.on('connection', (socket) => {
  console.log(socket.id);

  socket.on('join_room', (roomName) => {
    socket.join(roomName); // creates room with the name
    console.log('User Joined Room:', roomName);
  });

  socket.on('send_message', (data) => {
    console.log("data =", data);
    socket.to(data.room).emit('receive_message', data.content);
  });

  socket.on('disconnect', () => {
    console.log('USER DISCONNECTED')
  });
});

httpServer.listen(3002, () => console.log(`Socket.io test running on port 3002`))

app.js(客户端)

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

let socket = io('localhost:3002/');

function App() {
  // variables
  const [loggedIn, setLoggedIn] = useState(false);
  const [room, setRoom] = useState('');
  const [userName, setUserName] = useState('');
  const [message, setMessage] = useState('');
  const [messageList, setMessageList] = useState([]);

  // functions
  const connectToRoom = () => {
    console.log('button clicked');
    setLoggedIn(true);
    socket.emit('join_room', room); // join_room copied from backend
  }

  const sendMessage = () => {
    const data = {
      room: room,
      content: {
        author: userName,
        message: message
      }
    }
    Promise.resolve(socket.emit('send_message', data))
    .then(() => setMessage(''));
  }

  // setup
  useEffect(() => {
    socket.on('receive_message', data => {
      console.log(data);
    });
  }, []);

  return (
    <div className="App">
      {!loggedIn ?
        <div className="logIn">
          <div className="inputs">
            <input type="text" placeholder="Name..." value={userName} onChange={ev => setUserName(ev.target.value)} />
            <input type="text" placeholder="Room..." value={room} onChange={ev => setRoom(ev.target.value)} />
          </div>
          <button onClick={connectToRoom}>Enter Chat</button>
        </div> :
        <div className="chatContainer">
          <div className="messages">
            <h1>{room}</h1>
            {messageList.map((messageInfo, index) => 
              <div key={index} className="messageBox">
                <p>{messageInfo.author}:&nbsp;{messageInfo.message}</p>
              </div>
            )}
          </div>
          <div className="messageInputs">
            <input type="text" placeholder="Message..." value={message} onChange={ev => setMessage(ev.target.value)} />
            <button onClick={sendMessage}>Send</button>
          </div>
        </div>
      }
    </div>
  );
}

export default App;

【问题讨论】:

  • “未收到”我假设您的意思是 console.log(data); 没有输出任何内容?
  • @KelvinSchoofs 没错。只有在我在 app.js 文件中写了一些注释并保存后,它才会出现在控制台中......然后神奇地一切都继续正常工作......直到我刷新页面。
  • app.js 是您的服务器或客户端代码的一部分吗?
  • @KelvinSchoofs 客户 > github.com/jamespagedev/reactjs-with-socketio(我很厌倦在这个问题上发布这个 repo,因为 repo 的变化......)
  • 嗯不知道发生了什么。我认为服务器正在重新启动导致问题,但它是重新加载的客户端?但是热重载,而不是整页重载?

标签: node.js reactjs express socket.io


【解决方案1】:

我发现了问题。状态在客户端的两个不同位置进行管理。

对于useEffect 中的socket.on('receive_message', ...),除了当前浏览器的控制台(发送消息的浏览器)之外,这将显示在登录到当前房间的所有其他浏览器控制台上。

为了让它也显示在当前的控制台浏览器窗口中,我还需要在我提交它的位置添加状态。

const sendMessage = () => {
  const data = {
    room: room,
    content: {
      author: userName,
      message: message
    }
  }
  Promise.resolve(socket.emit('send_message', data))
  .then(() => console.log(data)) // <------- add this line here
  .then(() => setMessage(''));
}

这当然意味着setMessageList 需要在sendMessage()socket.on('receive_message',...)(在useEffect() 内)都被调用

但是,在socket.on('receive_message',...) 中调用setMessageList 时要小心。这样做的原因是因为它在单个 useEffect 中被调用一次,它捕获了调用该函数时的状态并且不会更新。换句话说,你不能使用setMessageList([...messageList, data]),因为这个函数只会从第一次调用这个函数时读取messageList

为了解决这个问题,我看到了两个选项...

  1. 您可以删除useEffect((...), []) 中的[],强制它在无限循环中运行(这似乎很昂贵)。
  2. 另一种选择是让后端的数据更新、保存,然后发送回setMessageList(data)(在socket.on('receive_message',...) 内)必须重新加载所有消息并重新渲染它们。 (看起来仍然很贵,但没有第一个选项那么贵)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-02
    • 1970-01-01
    • 2019-07-25
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    相关资源
    最近更新 更多