[Socket.IO] Double Emit/On 현상 확인 및 해결 방법

slight-snow·2023년 6월 19일
0

Socket.IO

목록 보기
1/1
post-thumbnail

✴︎
글을 쓰기에 앞서,
문제를 해결하고 보니 Double Emit Issue 라기보다는
Double On Issue 라고 보는 것이 가깝지 않나 생각이 듭니다.

구글링 결과 해당 현상을 Emit Events Twice 로 부르는 경우가 많아
편의상 제목에 Emit 도 추가하였습니다 :)


✓ Double Emit/On 현상 확인

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 메서드가 중복되어 작성되어 있는 곳은 없었다.


✓ Double Emit/On 원인 분석

Server Side의 코드를 여러모로 수정해보았지만 좀처럼 해결되지 않아서,
이번엔 Client Side에서 console을 이용하여 문제 발생 지점을 찾고자 하였다.

가능성이 높은 useEffect 내부에 console을 찍어보았다.

그 결과,
처음에 채팅방을 들어갔을 때는 socket.on 메서드가 실행되지 않고
이외의 부분만 useEffect에 의해 동작하는 것을 알 수 있다.

하지만!

메세지를 보내면 이처럼 socket.on 메서드가 두 번 실행되면서
현재 메세지 리스트에 수신한 메세지를 두 번 입력하는 것을 볼 수 있다.

Server Side 의 socket.emit 코드에 console을 찍어보았지만,
해당 코드에서는 console이 중복으로 출력되지 않았으니...
아무래도 useEffect 내부에 뭔가 조치를 취해줘야 할 것 같다.


✓ Double Emit/On 문제 해결

다행히 구글링을 통해 Stack Overflow 에서 그 답을 찾을 수 있었다!
( 검색을 생활화합시다... :D )

요컨대, useEffect 내부에 socket.on 메서드에 이어 socket.off 메서드를 통해
socket.io의 리스너가 꺼지도록 return 문을 작성해주어야 한다는 것이다.

그리하여 useEffect 내부에 위와 같이 return 문을 통해
socket.off 메서드가 실행되도록 코드를 추가해주었다.

새로고침을 하고 다시 메세지를 보내보았다.

드디어!
정상적으로 메세지가 한 번만 수신되고, 출력되는 것을 확인할 수 있었다.



✦  후일담

socket.io 튜토리얼 영상 댓글에도 해당 문제에 관한 얘기가 있어서 확인해보니
useEffect 로 더블 렌더링 현상을 마주한 경우 useMemo 를 사용해보라는 글이었다.

하지만 useMemo 를 사용했음에도 해당 현상이 좀처럼 고쳐지질 않아서
당황하고 있었을 찰나, 구글링을 통해 해결 방법을 찾을 수 있어서 다행이었다 :)

이전 프로젝트에서 다룰까 했다가 멈췄던 socket.io 를 직접 다뤄보고
메세지가 정상적으로 송수신되는 것을 확인해보니 기분이 묘하다.

성장했다는 느낌?!

아직 코린이이긴 하지만!
어제보다 성장한 오늘, 오늘보다 성장한 내일을 마주하다보면 언젠가 스스로를
많이 성장했다고 느낄 수 있을 것이라 믿는다.


profile
주니어 개발자의 기억을 위한 기록 :)

0개의 댓글