[React] WebSocket 통신하기

서준·2024년 5월 14일
2

React

목록 보기
4/4
post-thumbnail

전 포스팅에서는 웹소켓의 정의, 등장 배경, 동작방식, 한계점 등을 알아보았고, 이번 포스팅에선 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을 통해 지속적으로 감지합니다.
    useState가 아닌 useRef를 사용하는 이유는 웹소켓 연결이 생성될 때 컴포넌트를 리렌더링되어도 변경되지 않는 값이기 떄문에 WebSocket 연결을 지속적으로 감지하기에는 useRef를 사용하는 것이 더 적합합니다.

웹소켓 연결 활성화

 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 연결을 안정적으로 관리하고 종료하도록 설정하였습니다.

profile
하나씩 쌓아가는 재미

0개의 댓글