Skip to content

Knowledge: In WebSocket

ChanhyukPark-Tech edited this page Mar 3, 2022 · 2 revisions

[react] 리액트 웹소켓 Websocket - 컴포넌트 마운트시 바로 웹소켓 구동이 안되는 Error

문제상황

웹소켓 핸드쉐이킹 후 구독을 하는데 처음 컴포넌트가 마운트 될 때 웹소켓 연결이 되지 않았고, 코드를 한 번 아무곳이나 더미로 수정한 후 리액트의 핫 리로딩을 강제로 시켜줬을때 비로소 웹소켓 연결과 구독이 실행되었다. 한번 왜 강제로 리랜더를 시켜줘야할까?

프로젝트로 리액트에서 웹소켓을 이용할 일이 있었다. 백엔드는 스프링으로 구현되어있기 떄문에 스프링에 최적화된 stomp 를 사용했다.

인스타그램의 Direct Message 와 같은 기능을 구현하고 있어서 나의 이름으로 온 메시지를 항상 확인해야한다.그러므로 컴포넌트가 마운트 되자마자 나의 이름을 항상 구독하고 있어야한다.

sockjs-client 라이브러리와 stompjs 라이브러리를 사용했다.

문제해결

왜 강제로 리랜더를 시켜줘야 비로소 웹소켓이 연결 및 구동이 될까? 라는 고민을 했는데 처음에 핸드쉐이킹 하는 부분에 오류가 있었다.

image

원래는 위 사진과 같이 컴포넌트의 바깥쪽에 상수와 변수를 선언했다.

아래와 같이 Direct Component(웹소켓 연결하는 컴포넌트) 안에 핸드쉐이킹을 하는 변수와 상수를 선언해주자 useEffect 를 통해서 웹소켓 연결하는 코드가 제대로 실행되었다!

image

[react] 리액트 웹소켓 Websocket - sockjs - InvalidStateError: The connection has not been established yet

Websocket - sockjs - InvalidStateError: The connection has not been established yet

메시지를 보내는 부분의 코드는 다음과 같다.

const sendMessage =  () => {
        // Todo : axios

            stompClient.send("/pub/messages", {}, JSON.stringify({
                "message": message,
                "senderId": 7,
                "receiverId": 14,
                "roomId": 5,
            }));
        }
        setMessage("");
    };

위 처럼 코드를 작성하니 메세지를 보내는 trigger 를 발생시킬때마다 위와같은 오류가 나왔다.

async await 도 사용해보고 여러가지 찾아본결과 임의로 시간을 지연시키는 등 편법을 써봤지만 오류해결에는 도움이 안되었다.

위 에러문구를 잘 해석해보면 아직 웹소켓이 준비가 되지않았는데, 계속 trigger 를 시키니깐 오류가 난것이였다. 여러가지 찾아본 결과 Stomp.Client 안에는 ws.readyState 라는 integer 값이 있으며, 연결되었을 경우에(준비가된 경우) 1을 반환한다고 한다. 그 사실을 이용해서 새로운 함수를 만들어줬다! 이 함수를 이용해서 기존의 send 를 감싸줄 것이다! 코드는 직관적이다.

// 웹소켓이 연결될 때 까지 실행하는 함수
    function waitForConnection(stompClient:Stomp.Client, callback :any) {
        setTimeout(
            function () {
                // 연결되었을 때 콜백함수 실행
                if (stompClient.ws.readyState === 1) {
                    callback();
                    // 연결이 안 되었으면 재호출
                } else {
                    waitForConnection(stompClient, callback);
                }
            },
            1 // 밀리초 간격으로 실행
        );
    }

아까 send 만 있던 함수를 새롭게 정의한 waitForConnection 함수로 감싸주자

const sendMessage =  () => {
        // Todo : axios

        waitForConnection(stompClient,function() {
            stompClient.send("/pub/messages", {}, JSON.stringify({
                "message": message,
                "senderId": 7,
                "receiverId": 14,
                "roomId": 5,
            }));
        })
        setMessage("");
    };

위처럼하면 몇번이고 메세지를 보내도 아까와 같은 오류가 뜨지 않는것을 확인했다!

프로젝트가 끝나면 전체 웹소켓에 대한 글을 작성하겠습니다.

Clone this wiki locally