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

React与Node.js中Socket.IO无法正常接收数据问题求助

问题:Socket.IO前后端连接无法接收第二个JSON数据

我使用Socket.IO搭建Express/Node.js后端与React前端的连接,需求是点击按钮时接收后端发送的JSON数据。当前点击第一个按钮可收到含"hello"的JSON消息,但点击“Done with JSON”按钮后,无法收到第二个JSON消息,页面仅显示“Done with JSON”。

前后端代码

后端代码

//////server side
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');

const app = express();
const server = app.listen(8080);
const io = require('socket.io')(server, {
    cors: {
      origin: '*',
    }
});
PORT = 8080;

app.get('/', (req, res) => {
    res.send('Socket.IO Server Running');
});

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

    // 客户端能收到这条消息
    const firstJson = {message:"hello"};
    socket.emit("receiveJson", firstJson);

    socket.on('jsonProcessed', () => {
        console.log('Client has processed the first JSON.');
        setTimeout(() => {
            // 客户端收不到这条消息
            const secondJson = { message: 'This is your second JSON!' };
            socket.emit('receiveJson', secondJson);
        }, 1000); // 1秒延迟
    });
    
    socket.on('disconnect', ()=>{
        console.log('User disconnected');
    });
});

前端代码

//Client side
import React, {useRef, useState, useEffect} from 'react';
import { useNavigate } from 'react-router-dom';
import io from 'socket.io-client';
const Male = ({title})=>{
    const navigate = useNavigate();
    const socket = io('http://localhost:8080');

    const [jsonData, setJsonData] = useState(null);

    useEffect(()=>{
        socket.on('connect',()=>{
            console.log('Connection to server established');
        })
        socket.on('receiveJson',(data)=>{
            console.log('Received JSON from server: ', data);
            setJsonData(data);
        })
        return()=>{
            console.log("Disconnected from socket");
            socket.disconnect();
        }
    },[]);

    const handleJsonProcessing = () =>{
        console.log('Emitting jsonProcessed event');
        socket.emit('jsonProcessed');
        setJsonData(null);
    };
    
    return(
        <div>
            {jsonData ? (
                <div>
                    <pre>{JSON.stringify(jsonData, null, 2)}</pre>
                    <button onClick={handleJsonProcessing}>Done with JSON</button>
                </div>
            ) : (
                <p>No JSON data received.!!</p>
            )}
        </div>
    );
};

问题原因

核心问题在于Socket.IO实例的创建位置错误:在函数组件顶层直接创建socket实例,每次组件重新渲染(比如调用setJsonData(null)时)都会生成新的Socket.IO连接,旧连接被断开。而useEffect仅在组件挂载时执行一次,只给第一个socket实例绑定了receiveJson事件,后续新创建的socket没有绑定该事件,导致无法接收后端发送的第二个JSON。

解决方案

使用useRef保存Socket.IO实例,避免每次渲染重新创建连接,并确保事件监听绑定到正确的实例上:

修改后的前端代码

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

const Male = ({title})=>{
    const navigate = useNavigate();
    // 用useRef保存socket实例,避免重复创建
    const socketRef = useRef(null);
    const [jsonData, setJsonData] = useState(null);

    useEffect(()=>{
        // 在useEffect内初始化socket,确保只创建一次
        const socket = io('http://localhost:8080');
        socketRef.current = socket;

        socket.on('connect',()=>{
            console.log('Connection to server established');
        });

        socket.on('receiveJson',(data)=>{
            console.log('Received JSON from server: ', data);
            setJsonData(data);
        });

        return()=>{
            console.log("Disconnected from socket");
            socket.disconnect();
        };
    },[]);

    const handleJsonProcessing = () =>{
        console.log('Emitting jsonProcessed event');
        // 使用ref保存的socket实例发送事件
        socketRef.current.emit('jsonProcessed');
        setJsonData(null);
    };
    
    return(
        <div>
            {jsonData ? (
                <div>
                    <pre>{JSON.stringify(jsonData, null, 2)}</pre>
                    <button onClick={handleJsonProcessing}>Done with JSON</button>
                </div>
            ) : (
                <p>No JSON data received.!!</p>
            )}
        </div>
    );
};

说明

  • useRef创建的对象在组件整个生命周期内保持引用不变,不会随渲染重新创建,确保始终使用同一个Socket.IO连接。
  • 事件监听在useEffect内绑定到初始化的socket实例,卸载时断开连接,避免内存泄漏。
  • 发送事件时调用socketRef.current.emit,保证使用的是同一个连接实例,后端能正确响应并发送第二个JSON。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:39:50