You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用useEffect接收Socket.io消息不稳定及在线用户数异常求助

Socket.io聊天应用问题修复:消息展示不稳定与在线用户数异常

一、消息展示不稳定的问题修复

问题根源

  1. 异步状态更新导致旧值误用:useEffect中socket.on("receive_message")回调里,调用displayMessage(messageReceived)时,setMessageReceived(data)是异步操作,此时messageReceived仍是更新前的旧值,导致展示的不是最新消息。
  2. React中直接操作DOM的风险:通过document.querySelector获取DOM并手动创建节点的方式,违背React状态驱动渲染的理念,易造成DOM与状态不同步,引发不稳定展示。
  3. 不必要的监听重复绑定:useEffect依赖数组包含setMessageReceived,每次状态更新都会触发useEffect重新执行(先移除监听再绑定),可能导致消息丢失或重复监听。

修复代码(客户端)

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

function App() {
  const [messageReceived, setMessageReceived] = useState("");
  const [liveUsers, setLiveUsers] = useState(0);
  const [messagesList, setMessagesList] = useState([]);
  const [socket, setSocket] = useState(null);

  // 初始化Socket连接
  useEffect(() => {
    const newSocket = io.connect("http://localhost:3001");
    setSocket(newSocket);

    return () => {
      newSocket.disconnect();
    };
  }, []);

  // 监听Socket事件
  useEffect(() => {
    if (!socket) return;

    const handleReceiveMessage = (data) => {
      setMessageReceived(data);
      setMessagesList(prev => [...prev, data]);
    };

    const handleReceiveUsers = (data) => {
      setLiveUsers(data);
    };

    socket.on("receive_message", handleReceiveMessage);
    socket.on("receive_users", handleReceiveUsers);

    return () => {
      socket.off("receive_message", handleReceiveMessage);
      socket.off("receive_users", handleReceiveUsers);
    };
  }, [socket]);

  const sendMessage = () => {
    const textInput = document.querySelector('.textInput');
    const text = textInput.value.trim();
    if (!text) return;

    setMessagesList(prev => [...prev, text]);
    socket.emit("send_message", text);
    textInput.value = "";
  };

  return (
    <div className="App">
      <h2 className="text-white font-bold" style={{ color: "white", marginTop: 10 }}>
        在线用户: {liveUsers}
      </h2>
      <div className='messages' style={{ border: '1px solid #ccc', padding: '10px', height: '300px', overflowY: 'auto' }}>
        {messagesList.map((msg, index) => (
          <div key={index}>{msg}</div>
        ))}
      </div>
      <input
        className="textInput text-gray-500 font-bold"
        style={{ height: 38, marginRight: 10, padding: 5, width: 1000 }}
        placeholder='消息'
      />
      <button
        id="name"
        className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
        onClick={sendMessage}
      >
        发送
      </button>
      <h1>最新消息: {messageReceived}</h1>
    </div>
  );
}

export default App;

二、在线用户数异常增加的问题修复

问题根源

  1. 断开连接时无法发送更新:用户断开时,socket.emit("receive_users", count)无法成功发送(此时socket已断开),导致其他客户端无法同步用户数减少的状态。
  2. 连接时仅通知当前用户:新用户连接时,仅通过socket.emit通知当前用户,其他在线用户无法同步最新在线数。

修复代码(服务端)

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

app.use(cors());
const server = http.createServer(app);

const io = new Server(server, {
    cors: {
        origin: "http://localhost:3000",
        methods: ["GET", "POST"],
    },
});

let count = 0;

io.on("connection", (socket) => {
    console.log(`用户已连接: ${socket.id}`);
    count++;
    // 通知所有客户端更新在线用户数
    io.emit("receive_users", count);

    socket.on("send_message", (data) => {
        socket.broadcast.emit("receive_message", data);
    });

    socket.on("disconnect", () => {
        console.log("用户已断开连接");
        count--;
        // 通知所有客户端更新在线用户数
        io.emit("receive_users", count);
    });
});

server.listen(3001, () => {
    console.log("监听端口3001")
});

内容的提问来源于stack exchange,提问作者jlc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 04:35:58