导读:本期聚焦于小伙伴创作的《如何用Context API和Socket.IO实现房间内用户列表展示》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用Context API和Socket.IO实现房间内用户列表展示》有用,将其分享出去将是对创作者最好的鼓励。

在实时聊天、多人协作等场景中,房间内用户列表的实时展示是核心需求之一,结合React的Context API和Socket.IO可以高效实现这个功能,既保证状态管理的简洁性,又能满足实时通信的要求。

如何用Context API和Socket.IO实现房间内用户列表展示

核心实现思路

整体实现分为服务端和客户端两部分:服务端通过Socket.IO管理房间和用户状态,监听用户加入、离开房间的事件并广播更新后的用户列表;客户端通过Context API定义用户列表的全局状态,连接Socket.IO监听服务端推送的用户列表更新事件,同步更新Context中的状态,再让需要的组件消费Context数据完成展示。

服务端实现

基础环境搭建

首先初始化Node.js项目,安装依赖:

// 初始化项目后执行安装命令
// npm install express socket.io

房间与用户管理逻辑

服务端需要维护房间和用户的关系,这里用一个对象存储每个房间对应的用户列表:

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

const app = express();
const server = http.createServer(app);
const io = new Server(server, {
  cors: {
    origin: "*",
    methods: ["GET", "POST"]
  }
});

// 存储房间用户列表 结构: { roomId: [userId1, userId2] }
const roomUsersMap = {};

// 处理用户加入房间
const handleJoinRoom = (socket, roomId, userId) => {
  // 如果用户已经在其他房间 先离开原房间
  Object.keys(roomUsersMap).forEach(room => {
    if (roomUsersMap[room].includes(userId)) {
      roomUsersMap[room] = roomUsersMap[room].filter(id => id !== userId);
      socket.leave(room);
      // 广播原房间用户列表更新
      io.to(room).emit('room_users_update', roomUsersMap[room]);
    }
  });
  // 加入新房间
  socket.join(roomId);
  if (!roomUsersMap[roomId]) {
    roomUsersMap[roomId] = [];
  }
  if (!roomUsersMap[roomId].includes(userId)) {
    roomUsersMap[roomId].push(userId);
  }
  // 向新房间广播更新后的用户列表
  io.to(roomId).emit('room_users_update', roomUsersMap[roomId]);
};

// 处理用户离开房间
const handleLeaveRoom = (socket, roomId, userId) => {
  if (roomUsersMap[roomId]) {
    roomUsersMap[roomId] = roomUsersMap[roomId].filter(id => id !== userId);
    socket.leave(roomId);
    // 广播房间用户列表更新
    io.to(roomId).emit('room_users_update', roomUsersMap[roomId]);
  }
};

io.on('connection', (socket) => {
  console.log('新用户连接:', socket.id);

  // 监听加入房间事件
  socket.on('join_room', ({ roomId, userId }) => {
    handleJoinRoom(socket, roomId, userId);
  });

  // 监听离开房间事件
  socket.on('leave_room', ({ roomId, userId }) => {
    handleLeaveRoom(socket, roomId, userId);
  });

  // 监听断开连接事件
  socket.on('disconnect', () => {
    // 遍历所有房间 移除断开连接的用户
    Object.keys(roomUsersMap).forEach(roomId => {
      const userIndex = roomUsersMap[roomId].findIndex(id => id === socket.id);
      if (userIndex !== -1) {
        roomUsersMap[roomId].splice(userIndex, 1);
        io.to(roomId).emit('room_users_update', roomUsersMap[roomId]);
      }
    });
    console.log('用户断开连接:', socket.id);
  });
});

server.listen(3001, () => {
  console.log('服务端运行在端口3001');
});

客户端实现

创建用户列表Context

首先定义Context,包含用户列表状态和更新方法:

import React, { createContext, useContext, useState, useEffect } from 'react';
import { io } from 'socket.io-client';

// 创建Context
const RoomUsersContext = createContext();

// 创建Provider组件
export const RoomUsersProvider = ({ children }) => {
  const [roomUsers, setRoomUsers] = useState([]);
  const [socket, setSocket] = useState(null);

  // 初始化Socket连接
  useEffect(() => {
    const newSocket = io('http://127.0.0.1:3001');
    setSocket(newSocket);

    return () => {
      newSocket.close();
    };
  }, []);

  // 加入房间的方法
  const joinRoom = (roomId, userId) => {
    if (socket) {
      socket.emit('join_room', { roomId, userId });
      // 监听该房间的用户列表更新
      socket.on('room_users_update', (users) => {
        setRoomUsers(users);
      });
    }
  };

  // 离开房间的方法
  const leaveRoom = (roomId, userId) => {
    if (socket) {
      socket.emit('leave_room', { roomId, userId });
    }
  };

  return (
    <RoomUsersContext.Provider value={{ roomUsers, joinRoom, leaveRoom, socket }}>
      {children}
    </RoomUsersContext.Provider>
  );
};

// 自定义Hook方便消费Context
export const useRoomUsers = () => {
  const context = useContext(RoomUsersContext);
  if (!context) {
    throw new Error('useRoomUsers必须在RoomUsersProvider内使用');
  }
  return context;
};

组件中使用Context展示用户列表

在入口文件包裹Provider,然后在需要的组件中消费用户列表数据:

// 入口文件 App.js
import React from 'react';
import { RoomUsersProvider } from './RoomUsersContext';
import RoomUserList from './RoomUserList';

function App() {
  return (
    <RoomUsersProvider>
      <div className="app">
        <RoomUserList />
      </div>
    </RoomUsersProvider>
  );
}

export default App;

用户列表展示组件:

import React, { useEffect, useState } from 'react';
import { useRoomUsers } from './RoomUsersContext';

const RoomUserList = () => {
  const { roomUsers, joinRoom, leaveRoom } = useRoomUsers();
  const [roomId, setRoomId] = useState('');
  const [userId, setUserId] = useState('');

  // 模拟用户加入房间
  const handleJoin = () => {
    if (roomId && userId) {
      joinRoom(roomId, userId);
    }
  };

  // 模拟用户离开房间
  const handleLeave = () => {
    if (roomId && userId) {
      leaveRoom(roomId, userId);
    }
  };

  return (
    <div className="room-user-list">
      <div className="operation">
        <input
          type="text"
          placeholder="输入房间ID"
          value={roomId}
          onChange={(e) => setRoomId(e.target.value)}
        />
        <input
          type="text"
          placeholder="输入用户ID"
          value={userId}
          onChange={(e) => setUserId(e.target.value)}
        />
        <button onClick={handleJoin}>加入房间</button>
        <button onClick={handleLeave}>离开房间</button>
      </div>
      <h3>当前房间用户列表</h3>
      <ul>
        {roomUsers.map((user, index) => (
          <li key={index}>{user}</li>
        ))}
      </ul>
    </div>
  );
};

export default RoomUserList;

注意事项

  • 服务端需要做好跨域配置,避免客户端连接时出现跨域问题
  • 用户断开连接时要及时清理对应的用户数据,避免用户列表残留无效数据
  • Socket事件监听要注意避免重复绑定,防止多次触发更新逻辑
  • 如果项目中有多个房间相关的状态,可以扩展Context的内容,统一管理所有房间相关的全局状态

Context_APISocket.IO用户列表房间管理修改时间:2026-06-24 16:21:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。