React项目Socket.io房间聊天双向通信故障排查求助
React+Socket.io双向聊天问题解决方案
问题场景
- 用户登录后进入个人页面,点击目标用户消息按钮进入聊天界面
- 仅能发送消息,无法接收对方回复
- 测试日志显示消息已发送且属于同一房间ID,但双方无法收到消息
核心问题分析
- Socket实例不统一:父组件和聊天组件各自创建独立的Socket连接,父组件执行
join事件的Socket实例与聊天组件收发消息的Socket实例不是同一个,导致聊天组件的Socket未加入目标房间。 - 聊天组件未加入房间:即使房间ID正确,聊天组件的Socket未执行
join操作,无法接收房间内的广播消息。 - 未清理Socket监听:组件卸载时未移除Socket事件监听,可能引发内存泄漏和重复监听问题。
修正步骤
1. 统一Socket实例
将父组件创建的Socket实例传递给聊天组件,避免重复创建连接。
2. 聊天组件加入房间
在聊天组件的useEffect中执行join操作,确保当前Socket实例加入目标房间。
3. 清理Socket监听
组件卸载时移除receive_message监听,防止内存泄漏。
修正后代码
父组件代码调整
const socket = io('http://localhost:8080'); const roomId = [sender, profileFirstName + " " + profileLastName].sort().join('_'); const messageHandler = () => { setRenderMessage(!renderMessage); }; // 渲染Message组件时传入socket实例 {renderMessage ? ( <Message sender={sender} recipient={profileFirstName + " " + profileLastName} profilePicture={profileProfilePicture} roomId={roomId} socket={socket} // 传递统一的Socket实例 /> ) : (...)}
聊天组件代码调整
import { useEffect, useState, useRef } from 'react'; import { ArrowLongUpIcon } from '@heroicons/react/24/outline'; // 接收父组件传递的socket参数 export default function Message({sender, recipient, profilePicture, roomId, socket}) { const [message, setMessage] = useState(''); const [messages, setMessages] = useState([]); const bottomRef = useRef(null); const sendMessage = () => { if (message !== '') { const messageData = { sender: sender, recipient: recipient, message: message, time: new Date().getHours() + ':' + new Date().getMinutes(), room: roomId }; socket.emit('send_message', messageData); setMessages((list) => [...list, messageData]); setMessage(''); }; }; useEffect(() => { // 加入目标房间 socket.emit('join', roomId); // 定义消息接收处理函数 const handleReceiveMessage = (data) => { if (data.room === roomId) { setMessages((list) => [...list, data]); } }; // 绑定消息监听 socket.on('receive_message', handleReceiveMessage); // 组件卸载时清理监听和房间 return () => { socket.off('receive_message', handleReceiveMessage); socket.leave(roomId); }; }, [roomId, socket]); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); // 其余JSX结构保持不变... };
后端代码(无需修改)
后端逻辑本身正确,io.to(data.room).emit可正常广播消息至房间内所有连接:
const { Server } = require("socket.io"); const socket = (server) => { const io = new Server(server, { cors: { origin: "*", methods: ["GET", "POST"], }, }); io.on('connection', socket => { socket.on('join', room => { socket.join(room); console.log('joined room: ' + room); }); socket.on('send_message', (data) => { console.log(data); io.to(data.room).emit('receive_message', data); }); }); }; module.exports = socket;
内容的提问来源于stack exchange,提问作者Josh Haywood
相关产品推荐
相关产品推荐

