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

React.js与Node.js中Socket.IO事件未触发问题求助

问题分析与修复方案

核心问题梳理

  1. Socket.IO重复初始化:服务端根目录index.js中两次创建Socket.IO实例,导致连接事件被重复监听,自定义事件触发逻辑冲突。
  2. useEffect依赖缺失:客户端useSocket的useEffect未将user纳入依赖,登录后user状态更新时不会重新建立Socket连接,可能在user未初始化时就发送join事件。
  3. 用户存在判断逻辑错误:服务端socket/index.js中if (user.has(user.id))判断错误,应检查users Map是否存在该用户ID。
  4. 异步函数未加await:调用getChatters异步函数时未使用await,导致chatters是Promise对象而非数组,后续循环逻辑失效。
  5. Socket连接未清理:客户端useEffect未返回清理函数,页面卸载或依赖更新时会残留旧的Socket连接,导致事件监听混乱。

具体修复步骤

1. 修复服务端Socket.IO重复初始化问题

修改服务端根目录index.js,删除重复的Socket.IO实例创建与多余监听:

const express = require("express");
const config = require('./config/app')
const router = require('./router');
const bodyParser = require('body-parser');
const cors = require('cors');

const app = express();
const http = require("http");

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cors());
app.use(router);
app.use(express.static(__dirname + "/public"));
app.use(express.static(__dirname + "/uploads"));

const port = config.appPort;

const server = http.createServer(app);
const SocketServer = require("./socket")

// 仅保留SocketServer初始化逻辑
SocketServer(server);

server.listen(port, () => {
    console.log(`Server is running on port ${port}`)    
});

2. 修复客户端useSocket的依赖与连接清理

修改客户端socketConnect.js,添加user依赖并添加连接清理逻辑:

import { useEffect } from "react";
import socketIOClient from "socket.io-client"

function useSocket (user, dispatch) {
    useEffect(() => {
        // 用户未初始化时不建立连接
        if (!user) return;
        
        const socket = socketIOClient.connect("http://127.0.0.1:3000")

        socket.emit("join", user)

        socket.on("typing", (user) => {
            console.log("Event", user)
        })

        socket.on("friends", (friends) => {
            console.log("Friends", friends)
        })

        socket.on("online", (user) => {
            console.log("Online", user)
        })

        socket.on("offline", (user) => {
            console.log("Offline", user)
        })

        // 页面卸载或依赖更新时清理Socket连接
        return () => {
            socket.disconnect();
            socket.removeAllListeners();
        }
    }, [dispatch, user]) // 将user加入依赖项
}

export default useSocket

3. 修复服务端用户存在判断与异步调用问题

修改服务端socket/index.js中join事件的逻辑:

socket.on("join", async (user) => {
    let sockets = [];
    // 修正判断逻辑:检查users Map中是否存在当前用户ID
    if (users.has(user.id)){
        const existingUser = users.get(user.id)
        existingUser.sockets = [...existingUser.sockets, socket.id]
        users.set(user.id, existingUser);
        sockets = existingUser.sockets;
        userSockets.set(socket.id, user.id)
    } else {
        users.set(user.id, {id: user.id, sockets: [socket.id]})
        sockets.push(socket.id);
        userSockets.set(socket.id, user.id)
    }
    const onlineFriends = []; 

    // 添加await等待异步函数返回结果
    const chatters = await getChatters(user.id) 

    console.log(chatters);

    // 后续逻辑保持不变
    for (let i = 0; i < chatters.length; i++){
        if (users.has(chatters[i])){
            const chatter = users.get(chatters[i])
            chatter.sockets.forEach(sock => {
                try {
                    io.to(sock).emit("online",user);
                } catch (error) {}
            })
            onlineFriends.push(chatter.id)
        }
    }
    sockets.forEach(sock => {
        try {
            io.to(sock).emit("friends", onlineFriends)
        } catch (error) {}
    })

    console.log("New User Joined: ", user.firstName);
    io.to(socket.id).emit("typing", "User typing...")
})

验证修复效果

  1. 重启服务端,登录多个用户,检查控制台是否正常打印online、friends等事件日志。
  2. 测试用户下线时,其他在线用户是否能收到offline事件提示。
  3. 切换页面后检查Socket连接是否被正常清理,避免残留连接导致的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 06:24:56