React组件创建时useEffect内socket连接不生效刷新后正常问题
问题根因
- 依赖项缺失:触发
join_room事件的useEffect依赖了未声明的username变量,首次加载时AuthContext未完成初始化,username为空值,导致首次加入房间请求无效;刷新页面时登录态已从本地存储读取完成,username有有效值,所以请求正常。 - 未等待socket连接完成就发事件:
io()创建socket实例是同步操作,但和服务端建立WebSocket连接是异步过程,实例创建完成不代表连接已成功,此时emit的事件会被服务端忽略。 - 冗余依赖:当前触发加入房间逻辑的useEffect里声明了
user作为依赖,但整个逻辑中没有用到user变量,会导致不必要的重复执行。
修复方案
- 把
username加入useEffect依赖数组,确保只有登录态完成初始化、拿到有效用户名后才触发加入房间逻辑 - 监听socket的
connect事件,确认连接成功后再发送join_room事件 - 增加useEffect清理逻辑,组件卸载时主动断开socket连接,避免内存泄漏和重复连接
- 只有当用户处于登录态时才初始化socket连接,避免未登录用户创建无效连接
修改后代码
function App() { const authCtx = useContext(AuthContext) const username = authCtx.username const [socket, setSocket] = useState(null); // 只有登录后才初始化socket useEffect(() => { if (authCtx.isLoggedIn) { const newSocket = io("http://localhost:7000"); setSocket(newSocket); // 组件卸载时断开连接 return () => { newSocket.disconnect(); setSocket(null); } } }, [authCtx.isLoggedIn]); // 连接成功后再加入房间 useEffect(() => { // 确保socket存在、已登录、username有值 if (!socket || !authCtx.isLoggedIn || !username) return; const handleConnect = () => { socket.emit("join_room", { chatroom: username }); } // 如果已经连接成功直接触发,否则监听connect事件 if (socket.connected) { handleConnect(); } else { socket.on('connect', handleConnect); } // 清理事件监听 return () => { socket.off('connect', handleConnect); } }, [socket, authCtx.isLoggedIn, username]); return ( <div> {authCtx.isLoggedIn && socket && <MainNavigation socket={socket} />} {authCtx.isLoggedIn && <FloatingBtn/>} <Switch> {authCtx.isLoggedIn && socket && <Route exact path='/Chat'> <Chat socket={socket} /> </Route>} </Switch> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者Shivam Sharma
相关产品推荐
相关产品推荐

