• IceCraft - 방 만들기 모달창 리팩토링

    2024. 7. 3.

    by. 서카츄

    소켓부분을 커스텀 훅으로 리팩토링이 진행됨에 따라

    메인페이지, 메인페이지에서 방 생성하는 모달창 리팩토링을 진행하였다.

     

     

    이전 코드

    useEffect(() => {
        socket.on("createRoom", ({ room_id }) => {
          roomId.current = room_id;
          socket.emit("joinRoom", userId, room_id, nickname);
        });
    
        socket.on("createRoomError", (message) => {
          toast.error(message);
          isGoInClick.current = false;
        });
    
        socket.on("joinRoom", () => {
          if (roomId.current) {
            setRoomId(roomId.current);
            setIsCreate(false);
            if (selectedGame === "마피아") {
              router.push(`/room/${roomId.current}/`);
            }
            return null;
          }
        });
    
        socket.on("joinRoomError", (message) => {
          toast.error(message);
          isGoInClick.current = false;
        });
    
        return () => {
          socket.off("createRoom");
          socket.off("createRoomError");
          socket.off("joinRoom");
          socket.off("joinRoomError");
        };
      }, []);

     

    이전코드에서는 그대로 socket.on으로 연결하고

    socket.emit 보내고

    socket.off 로 언마운트 되면 종료시키는 내용을 전부 담고 있었다.

    일일이 한줄씩 써주고 있었던 내용들을 커스텀 훅으로 변경함에 따라,

    메인페이지도 리팩토링을 진행하게 되었다.

     

     

     

    리팩토링 - 커스텀 훅으로 변경

      const createSocket = {
        createRoom: ({ room_id }: CreateRooms) => {
          roomIdRef.current = room_id;
          socket.emit("joinRoom", userId, roomIdRef.current, nickname);
        },
        createRoomError: (message: string) => {
          toast.error(message);
          isGoInClick.current = false;
        },
        joinRoom: () => {
          if (roomIdRef.current) {
            setRoomId(roomIdRef.current);
            setIsCreate(false);
            router.push(`/room/${roomIdRef.current}/`);
          }
        },
        joinRoomError: (message: string) => {
          toast.error(message);
          isGoInClick.current = false;
        }
      };
      useSocketOn(createSocket);

     

    훨씬 코드가 깔끔해졌다...!

     

     

     

     

     

    커스텀훅으로 변경하고,  메인페이지 방 만들기 모달창은

    방 이름과 인원수를 선택하고 확인 버튼을 눌렀을때,

    방 만들기 핸들러가 실행되면서 서버에 "createRoom"을 보내주고

    "joinRoom"에 있는 내용들을 보내 주어야 했다.

     

     

     

     

     

    방 만들기 핸들러(확인버튼) 코드

      //NOTE - 방 만들기 핸들러
      const createRoomSubmitHandler = async (e: FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        try {
          if (!roomTitle.trim()) {
            toast.error("방 제목을 입력해 주세요.");
            return;
          }
          if (!isGoInClick.current && selectedGame === "마피아") {
            isGoInClick.current = true;
            socket.emit("createRoom", roomTitle, selectedGame, numberOfPlayers);
            setSelectedGame("마피아");
            setRoomTitle("");
            setNumberOfPlayers(5);
            return;
          } if (!isGoInClick.current && selectedGame === "노래맞추기") {
            toast("노래 맞추기 게임은 준비중입니다.");
            return;
          }
        } catch (error) {
          console.log("error", error);
        }
      };

     

    리팩토링한 방 만들기 핸들러 코드이다.

    하지만 여기서 문제가 발생하는데....

     

     

    사용자가 방 내용을 입력하고 확인 버튼을 누르면

    socket.emit("createRoom", roomTitle, selectedGame, numberOfPlayers);

     

    클라이언트측에서 서버에 사용자가 입력한 내용을 보내주면,

    서버에서는 "createRoom" 에 대한 수신을 받고 난 뒤

    서버에서 다시 클라이언트에게 "JoinRoom"을 송신해준다!

    그러면 클라이언트측에서는 서버에서 기다렸다가 "JoinRoom"을 받아오는 구조였다. 

       

     

     

    그림으로 설명하면 이렇게 순서대로 클라이언트와 서버간 이렇게 socket.io로 양방향 통신 순서를 진행 하고 있는데

    문제는 방 만들기 버튼을 누르자마자

    클라이언트에서 "createRoom" 내용과 "JoinRoom" 내용을 전부 보내줘버렸다 ^_ㅠ

     

     

     

     

     

    그림대로 이렇게 한꺼번에 보내주고 있다는 사실...!

    이렇게 묶어서 보내주다보니

    서버에서 createRoom을 클라이언트에서 받아왔으면,

    "joinRoom" 메서드를 클라이언트에게 줘야하는데

     

    클라이언트측에서 한꺼번에 createRoom과 joinRoom을 동시에 보내주다보니

    joinRoom에서 서버에서 보내줄 roomId 의 값이 undefined으로 뜨는 현상이 일어나고 말았다.

     

     

    처음에는 방 만들기 핸들러에 emit으로 서버에게 보낼 때,

    "createRoom"에 대한 정보와 "joinRoom"값을 동시에 보내주었는데

    방 만들기 핸들러에서는 "createRoom"에 대한 정보를 먼저 보내주도록 수정하였다.

     

    방 만들기 모달창 핸들러

    if (!isGoInClick.current && selectedGame === "마피아") {
           isGoInClick.current = true;
           socket.emit("createRoom", roomTitle, selectedGame, numberOfPlayers);
           클라이언트에서 처리 할 내용(중략)
           return;
    }

     

    그리고 서버에서 "createRoom" 메서드를 수신하고 난 뒤,

    useRef로 room_id값을 넣고, roomId 값을 받아오고 나서,

    "joinRoom"으로 보내주는 방식으로 진행하였다.

     

     

    createRoom 소켓 이벤트

      createRoom: ({ room_id }: CreateRooms) => {
          roomIdRef.current = room_id;
          socket.emit("joinRoom", userId, roomIdRef.current, nickname);
        },

     

    서버에서 "createrRoom"을 수신하면,

    roomId 값을 useRef에 저장해두고,

    "joinRoom" 에 대한 내용을 송신한다.

     

     

    joinRoom 소켓 이벤트

      joinRoom: () => {
          if (roomIdRef.current && selectedGame === "마피아") {
            setRoomId(roomIdRef.current);
            setIsCreate(false);
            setIsEntry(true);
            router.push(`/room/${roomIdRef.current}/`);
          }
        },

     

    현재 roomId에 값이 있고, 게임 이름이 마피아인 경우 RoomId값을 저장한다.

    그리고 사용자가 방을 생성하고 들어가면, joinRoom이벤트가 실행되어

    해당방으로 이동할 수 있도록 router.push를 넣어준다.

     

    클라이언트에서 emit으로 createRoom을 먼저 받고, 그뒤로 RoomId 값이 들어오면 진행할 수 있도록

    콜백함수로 시도를 해보았는데,

    joinRoom에 있는 내용을 송신하면 서버에서 joinRoom에 대한 내용의 값을 전부 인식을 못했다.

    알고보니 서버에서 코드도 같이 콜백함수로 맞춰줘야 joinRoom을 받을 수 있었다...ㅠㅠ

     

     

    어찌저찌 결과는 쉽게 해결한거 같지만 처음에 삽질을 엄청했다 ㅜㅜ

    서로 송수신하면서 코드파악을 하고 적용하는데 시간이 오래걸렸다.

    계속 console.log로 추적해보고 고민해보고 서버코드도 확인해보면서 해결하게 되었다.

    댓글