[React] socket.io로 통신

5

리액트

목록 보기
9/14
post-thumbnail

🙆🏻‍♀️ [React] socket.io로 통신 🙆🏻‍♀️

socket.io

자바스크립트에는 서버와 양방향 통신을 위한 웹소켓 API가 있다.
socket.io는 웹소켓을 활용하여 통신을 보다 쉽게 할 수 있는 라이브러리다.

socket.io 공식 사이트

서버의 상태나 실시간 알림을 위해 사용했는데, 두고두고 쓰일 것 같아
코드와 함께 기록한다. 클라이언트 부분만...☆



클라이언트 예제

socket.io를 사용할 거라면 서버와 클라이언트 모두 패키지를 설치해야 한다.

yarn add socket.io-client

공통으로 쓰기 위해 따로 socketio.js 파일을 생성한다.
총 4개의 socket.io 함수를 사용했다.

구현 중에 각각 다른 이벤트(감시, 알림)인데 데이터가 제대로 들어오지 않았다.
데이터가 중복으로 들어온다든가 제대로 끊어지지 않는다든가...☆
Map을 선언해서 cbType, cb로 설정한 뒤에 for... of로 결과 값을 담았다.

  • socket.connect(): 소켓 연결.
  • socket.emit("이벤트 명", Data): 이벤트 명을 지정하고 데이터를 보냄.
  • socket.on("이벤트 명", 콜백 함수): 해당 이벤트를 받고 콜백함수를 실행.
  • socket.disconnect(): 소켓 연결을 끊음.
// socketio.js

import { io } from "socket.io-client";

export let socket = io("http://서버 IP:서버 포트", { transports: ["websocket"] });
export const initSocketConnection = () => {
  if (socket) return;
  socket.connect();
};

// 이벤트 명을 지정하고 데이터를 보냄
export const sendSocketMessage = (cmd, body = null) => {
  if (socket == null || socket.connected === false) {
    initiateSocketConnection();
  }
  socket.emit("message", {
    cmd: cmd,
    body: body,
  });
};


let cbMap = new Map();

// 해당 이벤트를 받고 콜백 함수를 실행함
export const socketInfoReceived = (cbType, cb) => {
  cbMap.set(cbType, cb);
  
  if (socket.hasListeners("message")) {
    socket.off("message");
  }

  socket.on("message", ret => {
    for (let [, cbValue] of cbMap) {
      cbValue(null, ret);
    }
  });
};

// 소켓 연결을 끊음
export const disconnectSocket = () => {
  if (socket == null || socket.connected === false) {
    return;
  }
  socket.disconnect();
  socket = undefined;
};

초기 연결 필요 없어짐!!!
초기 연결을 위해 부모 컴포넌트에서 socketio.js에 만들어 둔 initSocketConnection, disconnectSocket을 import 한다.
useEffect 훅으로 초기 렌더링 시에만 소켓을 연결하고 리턴 함수에 소켓 연결을 끊는다.

// parents.jsx
import { initSocketConnection } from "../../socketio"
...

useEffect(() => {
  initSocketConnection();
  
  return () => {
    disconnectSocket();
  }
}, []);

...

// 2022. 04 수정

sendSocketMessage, socketInfoReceived를 import한다.
두 함수를 함께 묶어 socketData를 만든다.
소켓을 연결한 채로 a에 진입하면 a에 대한 데이터를 주고 a를 나오면 주는 것을 멈춰야 했다.

useEffect 훅으로 렌더링 후 cmd코드와 body를 socketData 인자에 담아 호출한다.
리턴 함수에는 "a에 대한 데이터 그만 보내줘~" 로 미리 약속한 cmd코드를 sendSocketMessage body와 함께 인자에 담아 호출한다.

해당 훅은 초기 렌더링과 userIdx가 변경 되었을 때 수행한다.

// chidren.jsx
...

const socketData = (cmd, body) => {
  sendSocketMessage(cmd, body);
  socketInfoReceived(104, (err, ret) => {
    if (err) {
      console.error(err);
      return;
    }
    if (ret.cmd === 119) {
      // do something... 
    }
   });
};


useEffect(() => {
  const body = { userIdx: Number(userIdx) };
  socketData(118, body);
  
  return () => {
    sendSocketMessage(120, body);
  };
}, [userIdx]);

...
profile
당당하게 외치고 싶어요. "나, 「프런트엔드 개발자」야" 라고...😏

0개의 댓글