자바스크립트에는 서버와 양방향 통신을 위한 웹소켓 API가 있다.
socket.io는 웹소켓을 활용하여 통신을 보다 쉽게 할 수 있는 라이브러리다.
서버의 상태나 실시간 알림을 위해 사용했는데, 두고두고 쓰일 것 같아
코드와 함께 기록한다. 클라이언트 부분만...☆
socket.io를 사용할 거라면 서버와 클라이언트 모두 패키지를 설치해야 한다.
yarn add socket.io-client
공통으로 쓰기 위해 따로 socketio.js 파일을 생성한다.
총 4개의 socket.io 함수를 사용했다.
구현 중에 각각 다른 이벤트(감시, 알림)인데 데이터가 제대로 들어오지 않았다.
데이터가 중복으로 들어온다든가 제대로 끊어지지 않는다든가...☆
Map을 선언해서 cbType, cb로 설정한 뒤에 for... of로 결과 값을 담았다.
// 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]);
...