먼저 기존 디자인의 레이아웃 가이드라인들을 모두 지웠다. 그리고 각 사용자의 메시지를 식별하기 위해서 그 클라이언트의 socket id를 표시하도록 했다. (타인의 메시지만 보이게 카카오톡을 참고하였다.) 많이 깔끔해진거 같다.
추가적으로 채팅 모듈이 아닌 데모버전에서는 width사이즈를 3가지를 선택하여서 채팅창이 반응형으로 변하는 것을 볼 수 있도록 추가했다. 기본적으로 채팅창 구성요소는 모두 플렉스 레이아웃에 반응형을 기준으로 했기 때문에 극한의 디바이스 환경이 아닌 이상 어디서든 무난하게 맞춰진다.
웹챗 데모 버전 링크
https://yoonjonglyu.github.io/webChat/
소켓 서버 연결에 대한 피드백을 제공하기 위해서 ui를 넣었다. 현재 상태로는 간단하게 2가지 문구로 연결중 상태와 연결실패 및 해제 상태를 피드백 해준다. 해당 부분은 css 애니메이션 같은 것을 넣어서 조금 동적으로 보이게 해줘야겠다.
현재는 아래와 같다.
이 과정에서 리액트 훅 테스트 와 비동기 테스트가 너무 힘들었는데 아직 명확한 답을 못내고 있다. ㅜㅜ
또한 기존의 채팅 메시지 송수신 관한 이벤트 리스닝 관해서 편법으로 처리한 부분을 아래와 같이 1회용 리스닝과 리스너 해제를 통해서 변경 해줬다. 기존의 방식은 useState와 useEffect훅 사이의 컨텍스트가 서로 연동이 안되었기에 메모리 누수라는 취약점이 존재했었지만 결국 중복 리스닝이 문제였기에 once를 사용하고 remove리스너를 사용해서 이벤트 리스닝 관련한 부분을 해결했다.
useEffect(() => {
const handleChatLog = (msg: { idx: string, message: string }) => {
setChatLog([...chatLog, msg]);
}
socket.once('receive', (data: { idx: string, message: string }) => {
if (socket.connected) {
handleChatLog(data);
}
});
socket.once('joinRoom', (id: string) => {
if (socket.connected) {
handleChatLog({
idx: '#system',
message: `${id} 님이 대화에 참여 하였습니다.`,
});
}
});
socket.once('leaveRoom', (id: string) => {
if (socket.connected) {
handleChatLog({
idx: '#system',
message: `${id} 님이 대화에서 나갔습니다.`,
});
}
});
return () => {
socket.removeAllListeners('receive');
socket.removeAllListeners('joinRoom');
socket.removeAllListeners('leaveRoom');
}
});
초기버전 배포 이후 추가적인 기능 업데이트 및 수정을 위해서 기존의 벡엔드와 주고 받던 소켓 이벤트를 조금 고쳤다.
중간에 기능이나 절차가 추가 될 경우 이벤트를 주고 받는 플로우가 변경 될 수 있는데 버전 업데이트 마다 벡엔드 로직을 많이 변경한다면 그건 별로 긍정적으로 느껴지지 않았기에 최대한 절차를 쪼개서 추후 프론트엔드 채팅모듈이 업데이트되고 기능이 추가되더라도 벡엔드 소켓서버 로직을 최대한 건드릴 필요가 없게 할 필요가 있다.
@SubscribeMessage('join')
handleJoin(@MessageBody() data: { socketIdx: string, room: string }) {
this.logger.log(data);
this.server.socketsJoin(data.room);
this.usrList[data.socketIdx] = data.room;
this.server.to(data.room).emit('joinRoom', data.socketIdx);
}
@SubscribeMessage('send')
handleSend(@MessageBody() data: { socketIdx: string, message: string, room: string }) {
this.logger.log(data);
this.server.to(data.room).emit('receive', {
message: data.message,
idx: data.socketIdx
});
}
@SubscribeMessage('leave')
handleLeave(@MessageBody() data: { socketIdx: string, room: string }) {
this.logger.log(data);
delete this.usrList[data.socketIdx];
this.server.socketsLeave(data.room);
this.server.to(data.room).emit('leaveRoom', data.socketIdx);
}
afterInit(server: Server) {
this.logger.log('init');
}
handleDisconnect(client: Socket) {
this.logger.log(`Client Disconnected : ${client.id}`);
this.server.to(this.usrList[client.id]).emit('leaveRoom', client.id);
delete this.usrList[client.id];
}
handleConnection(client: Socket, ...args: any[]) {
this.logger.log(`Client Connected : ${client.id}`);
client.emit('room', Array.from(client.rooms));
}
쓸모 없던 init이벤트를 제거했고 커넥션 이벤트에서 대화방 입장 즉, 소켓 room을 고르던 이벤트를 따로 join부분으로 완전히 분리했다. (방목록은 그대로 보내주는게 맞을거 같아서 보내준다.) 또 대화방에서 벗어나는 경우 leave이벤트로 대화방 퇴장에 관한 로직 및 시스템 메시지를 관리하는데 그냥 바로 연결을 해제 할 경우 해당 사용자의 room 정보가 소실되어 버리기에 전체 메시지 말고는 방법이 없어서 따로 소켓서버에서 usrList 해시 구조를 통한 각 사용자가 어느 room에 들어가 있는지를 관리하기로 했다. 이 부분은 아직 잘 모르겠다. 조금 더 간단하고 좋은 구조가 있을려나?
해당 부분을 건드리면서 프론트엔드 비동기 테스트로 고생을 했는데 아직 잘 모르겠다. 기능 구현보다 테스트코드 작성이 더 힘든건 그냥 익숙하지 않아서인지 원래 그런것인지 잘모르겠다.
이 외에는 자잘한 테스트코드 수정이나 타입 변경 디렉토리 구조 변경 등이 있다. 채팅 패키지에 대한 초기 기획이 정해졌기에 배포를 위해서 준비하고 있다.
프론트엔드 Repo
https://github.com/yoonjonglyu/webChat
벡엔드 Repo
https://github.com/yoonjonglyu/webChat-server
'프로젝트' 카테고리의 다른 글
[JS]노션 기능을 간단히 따라 만들어보며 (0) | 2022.03.07 |
---|---|
[js-util] 바닐라 js로 프론트엔드 기능 개발하기. (0) | 2022.01.30 |
[웹챗] nest 소켓 서버 헤로쿠 배포 & 프론트 깃페이지 배포 (0) | 2021.12.05 |
[웹챗] 기본 테마 & 시스템 메시지 (0) | 2021.12.03 |
[웹챗] 채팅 메시지 성능 이슈 해결 & 채팅 메시지 기본 UI (0) | 2021.11.30 |