React + Socket.io:重复连接消息(Socket ID不同)的原因与解决
React严格模式下Socket.io重复连接的问题解析
1. 为什么严格模式会导致重复连接?
React严格模式仅在开发环境生效,它会刻意重复执行部分操作来排查潜在问题,包括组件的构造函数、render方法、useState/useReducer初始化函数,以及不带稳定依赖数组的useEffect。
如果你的前端Socket.io连接逻辑写在useEffect里且未正确处理清理,严格模式会触发两次useEffect执行:第一次创建socket连接后,严格模式会立即调用清理函数(若存在),随后再次执行useEffect创建第二个独立连接。后端因此收到两个不同的连接请求,自然会打印两次带不同ID的"User connected"日志。
2. 不关闭严格模式的修复方案
方案一:给useEffect添加清理函数
在创建socket的useEffect中返回清理函数,确保第一次创建的socket被正确销毁,只保留第二次执行后的稳定连接:
import { useEffect } from 'react'; import io from 'socket.io-client'; function ChatComponent() { useEffect(() => { const socket = io('http://localhost:3001'); // 这里添加socket事件监听等业务逻辑 // 清理函数:组件卸载或useEffect重新执行时断开连接 return () => { socket.disconnect(); }; }, []); // 空依赖数组确保仅在组件挂载时执行逻辑 return <div>Chat Component</div>; }
方案二:用Ref标记连接状态
通过Ref标记是否已建立有效连接,避免重复创建socket实例:
import { useEffect, useRef } from 'react'; import io from 'socket.io-client'; function ChatComponent() { const socketRef = useRef(null); const isConnectedRef = useRef(false); useEffect(() => { if (!isConnectedRef.current) { socketRef.current = io('http://localhost:3001'); isConnectedRef.current = true; // 这里添加socket事件监听等业务逻辑 return () => { socketRef.current?.disconnect(); isConnectedRef.current = false; }; } }, []); return <div>Chat Component</div>; }
方案三:确保useEffect依赖数组稳定
如果useEffect依赖了外部变量,要保证这些变量的引用稳定,避免因依赖频繁变化导致useEffect重复触发:
// 错误示例:每次渲染都会新建config对象,触发useEffect重复执行 useEffect(() => { const socket = io('http://localhost:3001', { transports: ['websocket'] }); }, [{ transports: ['websocket'] }]); // 正确示例:将配置放在组件外部,保证引用稳定 const socketConfig = { transports: ['websocket'] }; useEffect(() => { const socket = io('http://localhost:3001', socketConfig); return () => socket.disconnect(); }, []);
内容的提问来源于stack exchange,提问作者Arpit Sharma
相关产品推荐
相关产品推荐

