ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 실시간 채팅 구현
    개발공부/React 2024. 1. 24. 21:10

     

    본 글은 React에서 Websocket & STOMP 를 사용해 실시간 채팅을 구현한 내용입니다.

     

    Websocket, STOMP 모두 프로토콜이다.

    (자세히 알고 싶다면 링크를 타고 들어가서 확인해보면 될 거 같다.)

     

    두 가지 프로토콜이 어떤 특징을 가지고 있어서 실시간 채팅을 구현할 수 있는지 간단하게 정리해봤다.

    Websocket
    양방향 통신을 지원하며, 지속적인 연결을 통해 실시간 데이터 전송을 가능하게 해줌

    STOMP
    메시지 기반의 프로토콜로 쉬운 구현과 클라이언트-서버 간의 효과적인 양방향 통신을 제공

     

     

    실시간 채팅 구현

    두 프로토콜의 특징을 알아봤으니 이제 실제로 활용해서 기능을 구현해보려고 한다.

     

    먼저 단계를 설명하자면 아래와 같다.

    1. SockJS 객체를 생성합니다. (웹소켁 연결을 위한 객체 생성)
    2. STOMP 객체를 생성합니다. (STOMP 객체는 SockJS 객체를 기반으로 하여 웹소켓 통신을 위한 객체)
    3. STOMP 객체의 connect() 메서드를 사용하여 웹소켓 연결을 설정합니다.
    4. STOMP 객체의 subscribe() 메서드를 사용하여 채팅방을 구독합니다.
    5. STOMP 객체의 send() 메서드를 사용하여 채팅 메시지를 보냅니다.

     

    위의 단계를 코드로 구현하면 아래와 같다.

    import SockJS from "sockjs-client";
    import { CompatClient, Stomp } from "@stomp/stompjs";
    
    const ChatInputForm = () => {
    	// ... 생략
        
        // 1. SockJS 객체 생성
        const socket = new SockJS("주소");
        useEffect(() => {
            // 2. Stomp 객체 생성
            const stompClient = Stomp.over(socket);
            
            // 3. Stomp 객체 사용해 연결 설정
            stompClient.connect(
                {
                    Authorization: accessToken, // 토큰 넣어주기
                },
                () => {
                    client.current = stompClient;
                    
                    // 4. Stomp 객체의 subscribe 사용해 채팅방 구독
                    client.current.subscribe(
                        `/sub/chat/room/${selectChat}`,
                        (message) => {
                            if (message && message.body) {
                                var recv = JSON.parse(message.body);
                                setMsgList(recv);
                            }
                        },
                        {
                            Authorization: accessToken,
                            simpDestination: selectChat,
                        }
                    );
                }
            );
            return () => {
                if (client.current) client.current.disconnect(); // 컴포넌트가 언마운트되면 연결 종료
            };
        }, [selectChat]);
        
        // ... 생략
        
        const feedAddMutation = useMutation(addPhotoChatRoom, {
    		onSuccess: (response) => {
                const url = response.data.data;
                // 5. Stomp 객체의 send 사용해 채팅 메시지 전달
                client.current!.send("/pub/chat/message", {Authorization: accessToken}, JSON.stringify({type:"IMAGE" ,roomId: selectChat, message: inputValue, imageUrl: url}));
            },
        });
        
        // ... 생략
    };

     

     

    문제 발생?!

    사실 위의 방법이 실시간 채팅 구현할 때 흔히 사용되는 방법이라서 연결하는데 큰 어려움은 없었다.

     

    제일 고민이 많았던 부분은 오히려.. 채팅방 변경 시 바로 반영되지 않는 문제였다.

     

    첫 번째로 선택한 채팅을 제대로 동작하는데, 두 번째로 들어간 채팅은 정상적으로 작동하지 않았다.

    (내가 만들었던 프로젝트는 사용자가 여러 채팅방에 들어갈 수 있다.)

     

    이유를 찾아보니 이전 코드는 첫 렌더링될 때만 동작해서 채팅방이 변경되었을 때 STOMP 클라이언트 생성 및 연결 로직이 실행되지 않아서였다. (+ 연결 종료 로직도 없었음!)

     

    그래서 useEffect를 사용해 채팅방이 선택될 때마다 이전 연결은 종료하고 새롭게 생성 및 연결되도록 했다!

     

    사실 제일 기본인 내용인데 처음 해보는거라서 놓쳤었던 거 같다! ㅎㅎ

    다른 사람들은 내 글을 읽고 나와 같은 실수를 안했으면 좋겠다 :) 

    728x90

    '개발공부 > React' 카테고리의 다른 글

    [React] fetch와 axios  (0) 2024.03.25
    [React] useState, useReducer hook  (0) 2024.03.02
    상태 관리  (0) 2024.01.16
    DOM에 직접 접근하기 (useRef)  (0) 2023.10.26
    리액트 프로젝트 구조  (0) 2023.10.25
Designed by Tistory.