✴︎
글을 쓰기에 앞서,
문제를 해결하고 보니 Double Emit Issue 라기보다는
Double On Issue 라고 보는 것이 가깝지 않나 생각이 듭니다.구글링 결과 해당 현상을 Emit Events Twice 로 부르는 경우가 많아
편의상 제목에 Emit 도 추가하였습니다 :)
socket.io
를 활용하여 웹 채팅 어플리케이션을 만들던 중,
의도치 않게 채팅이 두 번 수신되는 현상을 확인했다.
위의 사진처럼 각각의 사용자가 전송버튼을 한 번만 눌렀음에도 불구하고
메세지의 수신은 두 번 이뤄지는 것을 발견할 수 있었다.
socket.io
를 활용한 코드는 아래와 같다.
#Client Side
//전송버튼을 눌렀을 때 실행되는 sendMessage 함수
const sendMessage = async () => {
let messageData;
if (message !== '') {
messageData = {
room: room,
author: name,
message: message,
time: String(new Date(Date.now()).getHours()).padStart(2, '0')
+ ':' + String(new Date(Date.now()).getMinutes()).padStart(2, '0'),
}
}
//socket.emit 메서드를 통해 Client > Server로 데이터를 전송
await socket.emit('send_message', messageData);
setMessageList((list) => [...list, messageData]);
}
useEffect(() => {
//socket.on 메서드를 통해 Server > Client로 데이터를 수신
socket.on('receive_message', (data) => {
setMessageList((list) => [...list, data]);
})
}, [socket])
#Server Side
io.on('connection', (socket) => {
//socket.on 메서드를 통해 Client > Server로 데이터를 수신
socket.on('send_message', (data) => {
console.log(data);
//socket.emit 메서드를 통해 Server > Client로 데이터를 전송
socket.to(data.room).emit('receive_message', data);
})
})
코드에서 socket.emit
이나 socket.on
메서드가 중복되어 작성되어 있는 곳은 없었다.
Server Side의 코드를 여러모로 수정해보았지만 좀처럼 해결되지 않아서,
이번엔 Client Side에서 console을 이용하여 문제 발생 지점을 찾고자 하였다.
가능성이 높은 useEffect
내부에 console을 찍어보았다.
그 결과,
처음에 채팅방을 들어갔을 때는 socket.on
메서드가 실행되지 않고
이외의 부분만 useEffect
에 의해 동작하는 것을 알 수 있다.
하지만!
메세지를 보내면 이처럼 socket.on
메서드가 두 번 실행되면서
현재 메세지 리스트에 수신한 메세지를 두 번 입력하는 것을 볼 수 있다.
Server Side 의 socket.emit
코드에 console을 찍어보았지만,
해당 코드에서는 console이 중복으로 출력되지 않았으니...
아무래도 useEffect
내부에 뭔가 조치를 취해줘야 할 것 같다.
다행히 구글링을 통해 Stack Overflow 에서 그 답을 찾을 수 있었다!
( 검색을 생활화합시다... :D )
요컨대, useEffect
내부에 socket.on
메서드에 이어 socket.off
메서드를 통해
socket.io
의 리스너가 꺼지도록 return
문을 작성해주어야 한다는 것이다.
그리하여 useEffect
내부에 위와 같이 return
문을 통해
socket.off
메서드가 실행되도록 코드를 추가해주었다.
새로고침을 하고 다시 메세지를 보내보았다.
드디어!
정상적으로 메세지가 한 번만 수신되고, 출력되는 것을 확인할 수 있었다.
socket.io
튜토리얼 영상 댓글에도 해당 문제에 관한 얘기가 있어서 확인해보니
useEffect
로 더블 렌더링 현상을 마주한 경우 useMemo
를 사용해보라는 글이었다.
하지만 useMemo
를 사용했음에도 해당 현상이 좀처럼 고쳐지질 않아서
당황하고 있었을 찰나, 구글링을 통해 해결 방법을 찾을 수 있어서 다행이었다 :)
이전 프로젝트에서 다룰까 했다가 멈췄던 socket.io
를 직접 다뤄보고
메세지가 정상적으로 송수신되는 것을 확인해보니 기분이 묘하다.
성장했다는 느낌?!
아직 코린이이긴 하지만!
어제보다 성장한 오늘, 오늘보다 성장한 내일을 마주하다보면 언젠가 스스로를
많이 성장했다고 느낄 수 있을 것이라 믿는다.