✨ 기억보다 기록을/트러블슈팅

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

서카츄 2024. 7. 3. 18:56

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

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

 

 

이전 코드

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로 추적해보고 고민해보고 서버코드도 확인해보면서 해결하게 되었다.