NestJS Socket.Io离开了房间,但仍收到消息

问题描述

我有三个房间,分别是General,TypeScript和nest。我要在第一个和第二个浏览器标签中加入“普通会议室”。当我决定从第二个选项卡离开General并加入TypeScript会议室时,即使我应该离开General仍会收到来自General的消息。当您切换到其他客户端正在使用的房间并离开它时,会发生该错误。我正在使用NodeJs,Socket.io,nestJS和React。

服务器

@WebSocketGateway()
 export class ChatGateway implements OnGatewayInit,OnGatewayConnection,OnGatewaydisconnect {
 
  @WebSocketServer() server: Server;
  private logger: Logger = new Logger('ChatGateway');
 
  @SubscribeMessage('msgToServer')
  handleMessage(client: Socket,message: { sender: string,room: string,message: string }): void {
    
   this.server.to(message.room).emit('msgToClient',message);
   this.logger.log(`msgToClient: ${message}`);
   

   
  }
  @SubscribeMessage('joinRoom')
  handleRoomJoin(client: Socket,room: string ) {
    client.join(room);
    client.emit('joinedRoom',room);
    this.logger.log(`Client joined ${room}`);
  }

  afterInit(server: Server) {
   this.logger.log('Init');
  }
 
  handledisconnect(client: Socket) {
   this.logger.log(`Client disconnected: ${client.id}`);
  }
 
  handleConnection(client: Socket,...args: any[]) {
   this.logger.log(`Client connected: ${client.id}`);
  }
  @SubscribeMessage('leaveRoom')
  handleRoomLeave(client: Socket,room: string ) {
    console.log(client.id);
   /*  console.log(client.rooms);
    console.log(client.adapter.rooms); */
    client.leave(room);
  /*   console.log(room); */
  /*   client.rooms = {};
    delete client.adapter.rooms[room]; */
    client.emit('leftRoom',room);
    this.logger.log(`Client left ${room}`);
  /*   console.log(client.adapter.rooms);
    console.log(client.rooms); */
   // console.log(client.adapter.rooms) 
    
  }
 }

客户

  const [state,setState] = useState({ sender: "",room: "",message: "" });
  const [chat,setChat] = useState([
    { sender: "Peter",room: "General",message: "test" },]);
  const socket = io(BASE_URL);
  const [room,setRoom] = useState({
    General: false,TypeScript: false,nestJS: false,});
  console.log(room);
  useEffect(() => {
    socket.on("msgToClient",(msg) => {
      setChat([...chat,{ ...msg }]);
    });
  });

  const onTextChange = (e) => {
    setState({ ...state,[e.target.name]: e.target.value });
  };

  const onMessageSubmit = (e) => {
    e.preventDefault();
    const { sender,room,message } = state;
    socket.emit("msgToServer",{ sender,message });
    setState({ message: "",sender: "",room: "" });
  };

  const toggleRoomMembership = (chatroom) => {
    const isMemberOfActiveRoom = (chatroom) => {
      return room[chatroom];
    };
    if (isMemberOfActiveRoom(chatroom)) {
      setRoom({ ...room,[chatroom]: false });
    
      socket.emit("leaveRoom",chatroom);
    } else {
      setRoom({ ...room,[chatroom]: true });

      socket.emit("joinRoom",chatroom);
    }
  };

  const renderChat = () => {
    return chat.map(({ sender,message },index) => (
      <div key={index}>
        <h3>
          {sender}: <span>{message}</span>
        </h3>
      </div>
    ));
  };

解决方法

原来的解决方案很简单。将套接字放入useEffect并为其创建状态。

const [socket,setSocket] = useState({});
     useEffect(() => {
    const socket = io(BASE_URL);
    setSocket(socket);
    socket.on("msgToClient",(msg) => {
      setChat([...chat,{ ...msg }]);
     
    });
    
  },[]);