[Come on]React-Native 웹소켓 연결 하기

Eloe·2023년 3월 12일
1

COME-ON-M

목록 보기
3/6

프로젝트에 웹소켓을 도입하기로 했다.
useContext를 사용하는 방식을 읽고 내가 원한 방식이어서 useContext로 세팅했다.
우리 프로젝트에서 웹소켓의 역할은 데이터의 변동을 알려주는 것이다.

  • 데이터의 변동 알람을 수신 받음 => 데이터 요청 API를 날림 식으로 웹소켓과 소통한다.
import { useAppSelector } from '@app/hooks';
import { REACT_APP_SOCKET_SERVER } from '@env';
import useAuth from '@hooks/useAuth';
import { Client } from '@stomp/stompjs';
import React, { useRef, useState, useEffect } from 'react';

const WebSocketContext = React.createContext<any>(null);

export { WebSocketContext };

export default function ({ children }: { children: React.ReactNode }) {
  const { getAccessToken } = useAuth();
  const token = useAppSelector(state => state.auth.accessToken?.token);
  const client = useRef<Client>();

  useEffect(() => {
    const stompConfig = {
      brokerURL: `ws${REACT_APP_SOCKET_SERVER}/ws-meetings?token=${token}`,
      debug: (frame: any) => console.log(frame),

      reconnectDelay: 5000,
      heartbeatIncoming: 4000,
      heartbeatOutgoing: 4000,
      forceBinaryWSFrames: true,
      appendMissingNULLonIncoming: true,
    };

    if (!client.current && token) {
      client.current = new Client(stompConfig);
      client.current.onConnect = () => {
        console.log(`connected to ${stompConfig.brokerURL}`);
      };
      client.current.onDisconnect = error => {
        console.log(`disconnected to  ${stompConfig.brokerURL}`);
        console.log(error);
      };
      client.current.onDisconnect = error => {
        console.log(`error to  ${stompConfig.brokerURL}`);
        console.log(error);
      };
    }
  }, [token]);

  return (
    <WebSocketContext.Provider value={client}>
      {children}
    </WebSocketContext.Provider>
  );
}

이런식으로 connect시의 활동을 작성하고 업데이트 메세지에 따라 상태가 변하도록 리덕스를 작성해줬다.

import { createSlice } from '@reduxjs/toolkit';

interface ISocket {
  message: {
    messageType: string;
    data: object;
  };
  votingUpdate: boolean;
  meetingUpdate: boolean;
  memberUpdate: boolean;
  onlineUserUpdate: boolean;
  onlineUserList: number[];
}

const initialState = {
  message: {
    messageType: '',
    data: {},
  },
  votingUpdate: false,
  meetingUpdate: false,
  onlineUserUpdate: false,
  memberUpdate: false,
  onlineUserList: [],
};
const socketSlice = createSlice({
  name: 'socket',
  initialState: initialState as unknown as ISocket,
  reducers: {
    onMessage: (state, action) => {
      const message = action.payload;
      const { messageType, data } = message;

      console.log(`messageType${messageType}`);
      console.log(data);

      if (messageType !== 'RESOURCE_UPDATED_EVENT') {
        state.onlineUserUpdate = true;
        state.memberUpdate = true;
        state.onlineUserList = data.userIds;

        return;
      }

      if (messageType === 'RESOURCE_UPDATED_EVENT')
        switch (data.meetingResourceType) {
          case 'MEETING_VOTING':
            state.votingUpdate = true;
            break;
          case 'SUBSCRIBE_MEETING_EVENT':
            state.meetingUpdate = true;
            break;
          case 'UNSUBSCRIBE_MEETING_EVENT':
            state.meetingUpdate = true;
            break;

          case 'MEETING_MEMBERS':
            state.memberUpdate = true;
            break;

          default:
            break;
        }
    },
    setVotingUpdateEnd: state => {
      state.votingUpdate = false;
    },
    setMeetingUpdateEnd: state => {
      state.meetingUpdate = false;
    },
    setMemberUpdateEnd: state => {
      state.memberUpdate = false;
    },
    setOnlineUserUpdateEnd: state => {
      state.onlineUserUpdate = false;
    },
  },
});

export const {
  onMessage,
  setVotingUpdateEnd,
  setMeetingUpdateEnd,
  setMemberUpdateEnd,
  setOnlineUserUpdateEnd,
} = socketSlice.actions;

export default socketSlice.reducer;

소켓에서 메세지를 받으면 상태를 업데이트 => 업데이트가 끝난후엔 ~END함수를 실행해서 다시 상태를 바꿔줘 다음에도 변화를 감지할 수 있게 한다.

  const connect = () => {
    client.onConnect = () => {
      log('log', '성공');
      getMeetingData();
      const subscription = client.subscribe(
        `/sub/meetings/${meetingId}`,
        async frame => {
          log('log', frame);
          const data = await JSON.parse(frame.body);

          dispatch(onMessage(data));
        },
      );
    };

    client.activate();
  };

미팅룸에 들어오면 실행하는 connect함수 미팅룸 스크린에 들어오면 소켓연결 요청과 구독을 동시에한다. 소켓에서 메세지가 오면 리덕스가 실행되고 => 리덕스의 상태를 받아오는 함수들이 실행된다.

profile
황새를 쫓는 뱁새를 좋아합니다.

0개의 댓글