전 포스팅에서는 웹소켓의 정의, 등장 배경, 동작방식, 한계점 등을 알아보았고, 이번 포스팅에선 React에서 WebSocket을 어떻게 사용했는지 기록하고자 합니다.
import { useEffect, useRef, useState } from 'react';
import Loader from './Loader';
export default function Cctv() {
const ws = useRef<WebSocket | null>(null);
const cctvUrl = 'wss://cctv.example.com' // cctv webSocekt Url
const [cctvData, setCctvData] = useState('');
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
ws.current = new WebSocket(cctvUrl);
ws.current.onopen = () => {
console.log('WebSocket connection opened.')
setIsLoading(false);
}
ws.current.onmessage = (event) => {
if (event.data) {
const base64ImageData = 'data:image/jpg;base64,' + event.data;
setCctvData(base64ImageData);
}
};
ws.current.onerror = () => console.log('WebSocket Error');
ws.current.onclose = () => {
console.log('Websocket connection is closed');
};
return () => {
if (ws.current && ws.current.readyState === 1) {
ws.current.close();
}
};
}, []);
return (
<div className='cctv-container relative'>
{isLoading && <Loader />}
<img
id='imageCCTV'
width='360'
height='220'
src={cctvData}
alt='CCTV'
className={`cctv-image rounded-lg ${isLoading ? 'hidden' : ''}`}
/>
</div>
);
}
const ws = useRef<WebSocket | null>(null);
useRef
훅을 사용하여 컴포넌트 랜더링 시 WebSocket 연결을 감지하고 해당 값을 ws
을 통해 지속적으로 감지합니다. useEffect(() => {
ws.current = new WebSocket(cctvUrl);
ws.current.onopen = () => {
console.log('WebSocket connection opened.')
setIsLoading(false);
}
ws.current.onmessage = (event) => {
if (event.data) {
const base64ImageData = 'data:image/jpg;base64,' + event.data;
setCctvData(base64ImageData);
}
};
ws.current.onerror = () => console.log('WebSocket Error');
ws.current.onclose = () => {
console.log('Websocket connection is closed');
};
return () => {
if (ws.current && ws.current.readyState === 1) {
ws.current.close();
}
};
}, []);
useEffect
훅을 사용하여 컴포넌트가 마운트될 때new WebSocket(cctvUrl)
을 통해 소켓을 생성한뒤 ws.current
로 실시간 연결을 진행합니다.
지난 포스팅에서도 다뤘듯 소켓이 정상적으로 생성되었으므로 아래 4개의 이벤트를 사용할 수 있게 됩니다.
open
– 연결이 성공적으로 되었을 때 발생message
– 데이터를 수신하였을 때 발생error
– 연결 상 에러가 생겼을 때 발생close
– 연결이 종료되었을 때 발생데이터 수선시 event를 감지해 event.data
값이 있다면 해당 데이터를 base64ImageData
에 담고 있습니다.
여기서 중요한 점은 WebSocket을 통해 전송되는 데이터는 주로 텍스트 기반 입니다. 하지만 CCTV 영상과 같은 이미지 데이터는 이진 형식 (컴퓨터 파일)으로 저장되어 있습니다. 이진 데이터를 텍스트 형식으로 전송하기 위해 Base64 인코딩이 필요하므로 'data:image/jpg;base64,
를 통해 변환하여 데이터는 URL 형태로 만들어지고, 이를 상태 변수인 cctvData에 업데이트합니다. 이렇게 업데이트된 cctvData는 JSX에서 이미지 태그의 src 속성에 할당되어 화면에 실시간 CCTV 영상이 표시됩니다.
return () => {
if (ws.current && ws.current.readyState === 1) {
ws.current.close();
}
};
언마운트 사이클인 clean up을 통해 WebSocket 연결이 활성화되어 있는 경우에만 연결을 종료하도록 하여 컴포넌트의 생명 주기 동안 WebSocket 연결을 안정적으로 관리하고 종료하도록 설정하였습니다.