问题描述
我有三个房间,分别是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 }]);
});
},[]);