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

Node.js+Express+React中io.emit正常但socket.emit失效问题求助

Socket.io中socket.emit('pong')无响应,io.emit('pong')正常的问题解决

问题现象

基于Node.js、Express、React和Socket.io实现ping-pong示例时,服务器端调用io.emit('pong')能正常触发客户端控制台打印,但调用socket.emit('pong')时客户端无任何输出。服务器可以正常接收到pingSocket和pingIo事件。

问题原因

客户端组件中,const socket = io()定义在组件函数内部,每次组件重新渲染(比如状态更新)都会创建新的Socket实例:

  • useEffect是空依赖数组,仅在组件首次渲染时,给第一个Socket实例绑定了pong事件监听;
  • 点击按钮调用sendPing时,使用的是当前渲染周期生成的新Socket实例——这个新实例没有绑定pong事件监听,因此服务器通过socket.emit('pong')给它发送消息时,客户端无法响应;
  • 而io.emit('pong')是给所有连接的Socket实例广播消息,第一个Socket实例虽已被组件“丢弃”但仍保持连接,所以会触发它的pong监听,控制台打印内容。

解决方案

使用useRef保存Socket实例,确保组件整个生命周期内复用同一个Socket连接:

修改后的客户端代码

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

// Main
const Test = () => {
    // 用useRef保存socket实例,避免每次渲染创建新连接
    const socketRef = useRef();
    const [isConnected, setIsConnected] = useState(false);

    // UseEffect
    /// Initialize the socket
    useEffect(() => {
        // 初始化socket实例
        socketRef.current = io();
        const socket = socketRef.current;

        // Connection
        socket.on('connect', () => {
            setIsConnected(true);
        });

        // Disconnection
        socket.on('disconnect', () => {
            setIsConnected(false);
        });

        // Pong
        socket.on('pong', () => {
            console.log("pong");
        });

        // Turning off socket
        return () => {
            socket.off('connect');
            socket.off('disconnect');
            socket.off('pong');
            socket.disconnect(); // 组件卸载时断开连接
        };
    }, []);


    //// Send a ping
    const sendPing = () => {
        socketRef.current.emit('pingSocket'); // 现在可以正常工作
        socketRef.current.emit('pingIo'); // 正常工作
    }


    return <button onClick={() => sendPing()}>
                Send ping
            </button>
}

export default Test;

说明

  • useRef的.current属性在组件整个生命周期内保持不变,确保useEffect中绑定事件的Socket实例,和sendPing中发送事件的Socket实例是同一个;
  • 组件卸载时添加socket.disconnect(),避免无用的连接占用资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:55:14