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

React前端无法接收后端Socket.io发送的信号求助

Socket.io 聊天应用:前端无法接收后端发出的信号

我学习Socket.io后搭建了一个全局聊天应用,前后端已完成,但React前端无法接收后端Socket.io发送的信号。经检查,后端能正常接收前端发送的信号,但前端收不到后端返回的信号。以下是相关代码:

服务端index.js

import express from 'express';
import cors from 'cors';
import http from 'http';
import dt from 'dotenv';
import {Server} from 'socket.io';
import userRoutes from './routes/userRoutes.js';
import {dbConnect} from './config/db.js'
import {errorHandler} from './middlewares/errorMiddleware.js'
const dotenv = dt.config();
import MSG from './models/messageModel.js';
const PORT = process.env.NODE_PORT || 5000;

const app = express();
app.use(express.urlencoded({extended : false}));
app.use(express.json());
app.use(cors());

const server = http.createServer(app);
dbConnect();

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

io.on('connection', (socket) => {
    socket.on('conn_made', async() => {
        const messages = await MSG.find();
        socket.emit('initload', {msg : messages});
    })

    socket.on('post', async(data) => {
        const message = await MSG.create(data);
        socket.emit('updatemsg', message);
    })
});

app.use('/api/user', userRoutes);

app.use(errorHandler);

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

Redux切片代码

import { createSlice } from "@reduxjs/toolkit";
import io from 'socket.io-client';
const socket = io.connect('http://localhost:8000/');

const initState = {
    messages : [],
    isLoading : false
}

export const messageSlice = createSlice({
    name : 'message',
    initialState : initState,
    reducers : {
        resetmsg : (state) => {
            state.messages = [];
            state.isLoading = false;
        },
        addInit : (state,action) => {
            state.isLoading = false;
            console.log(action.payload);
        },
        connect : (state) => {
            socket.emit('conn_made');
            state.isLoading = true;
        },
        post : (state,action) => {
            socket.emit('post', action.payload);
        },
        receive : (state,action) => {
            state.messages.push(action.payload);
        }
    }
});

export const {resetmsg,addInit,connect,post,receive} = messageSlice.actions;
export default messageSlice.reducer;

前端Mainchat组件代码

import React, { useState, useEffect } from 'react';
import {FaSignOutAlt, FaShare} from 'react-icons/fa';
import {logout} from '../features/auth/authSlice';
import { useNavigate } from 'react-router-dom';
import {useSelector, useDispatch} from 'react-redux';
import io from 'socket.io-client';
const socket = io.connect('http://localhost:8000/');
import {resetmsg , addInit , connect , post , receive } from '../features/messages/messageSlice';

const Mainchat = () => {
  const [connected, setConnected] = useState(false);
  const [text, setText] = useState("");
  const {user} = useSelector((state) => state.auth);

  const dispatch = useDispatch();
  const navigate = useNavigate();

  socket.on('initload', (data) => {
    const {msg} = data;
    dispatch(addInit(msg));
  })

  socket.on('updatemsg', (data) => {
    dispatch(receive(data));
  })

  const handleConnect = () => {
    dispatch(connect());
    setConnected(true);
  }

  const handleLogout = async () => {
    await dispatch(logout());
    dispatch(resetmsg());
    navigate('/login');
  }

  const onSend = () => {
    const msg = {user : user._id , text : text};
    dispatch(post(msg))
    setText("");
  }

  return (
    <section className='container flex flex-col p-4 mt-16 h-full w-[40vw] border-2 border-gray-300 rounded-lg'>
      <div className='flex flex-row justify-between mb-5'>
        <h1 className='text-3xl font-bold'>{connected ? "Connected." : "Disconnected."}</h1>
        <button onClick={handleLogout}><FaSignOutAlt /></button>
      </div>
      {connected ? (
        <div className='flex flex-col space-y-2'>
          <div className='h-[400px] border-y-2 overflow-y-scroll'>
          
          </div>
          <div className='flex flex-row justify-between'>
            <input value={text} onChange={(e) => setText(e.target.value)} className='w-96 border-2 border-black py-1 px-2 rounded-lg' type='text' placeholder='Type your Message...' />
            <button onClick={onSend}><FaShare/></button>
          </div>
        </div>
      ) : (
        <button onClick={handleConnect}>Connect</button>
      )}
      
    </section>
  )
}

export default Mainchat

问题排查与解决方案

1. 端口不匹配(核心问题)

后端默认运行在5000端口(PORT = process.env.NODE_PORT || 5000),但前端Redux切片和组件里都连接的是http://localhost:8000/,端口不一致导致前端无法接收到后端消息。

修复:将前端所有io.connect的地址改为http://localhost:5000/,或者修改后端端口为8000。

2. 重复创建Socket实例

Redux切片和Mainchat组件各自创建了独立的Socket连接:

  • 点击Connect时,Redux里的Socket发送了conn_made事件
  • 但Mainchat组件里的另一个Socket在监听initload和updatemsg,两个Socket不属于同一个连接,因此组件监听器收不到返回消息。

修复:创建共享Socket实例,统一管理:

// src/utils/socket.js
import io from 'socket.io-client';
const socket = io.connect('http://localhost:5000/');
export default socket;

然后在Redux切片和组件中导入该实例:

// Redux切片
import socket from '../utils/socket';

// Mainchat组件
import socket from '../utils/socket';

3. 组件监听器内存泄漏优化

在组件卸载时移除Socket监听器,避免内存泄漏:

useEffect(() => {
  const handleInitLoad = (data) => {
    const {msg} = data;
    dispatch(addInit(msg));
  };
  const handleUpdateMsg = (data) => {
    dispatch(receive(data));
  };

  socket.on('initload', handleInitLoad);
  socket.on('updatemsg', handleUpdateMsg);

  return () => {
    socket.off('initload', handleInitLoad);
    socket.off('updatemsg', handleUpdateMsg);
  };
}, [dispatch]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:21