탕스로그

4주차 미션 : react-messanger - 2 본문

회고/CEOS

4주차 미션 : react-messanger - 2

taaang 2022. 10. 30. 12:38

CEOS의 세번째 스터디에서는 채팅페이지 하나를 만드는 것이었다면,

 

CEOS의 네번째 스터디에서는 그 연장선으로

라우터를 사용해서 메인, 채팅방, 설정 화면을 오가는 SPA 만들기! 를 해보았다.

 

사실.. 3주차 때 나름 구조를 잘 잡아놨다고 생각했기 때문에..

라우터만 좀 하면 수월하겠다! 고 생각한 나를 매우 친다.. 생각보다 힘들었다.

 

이번 글은 바로 Key Questions 부터 시작하겠다! 조사해야할 개념은 다음과 같다.

 

1. Routing 이란?

네트워크적인 개념으로 설명하자면, '어떤 네트워크 안에서 통신 데이터를 보낼 때 최적의 경로를 선택하는 과정'이라고는 하는데,

좀 더 풀어서 쓰면 하나의 페이지에서 다른 주소로 이동하면 다른 페이지를 보여주는 것을 의미한다.

보통 프론트엔드에서 라우터를 쓴다!고 하면 한 페이지에서 다른 페이지로 이동할 때 페이지끼리 연결하는 도구..? 정도로 생각하면 될 것 같다. 나는 라우터를 사용하기 위해 react-router-dom을 설치해서 페이지끼리 이동하였다.

 

2. SPA 란?

SPA의 반대되는 개념으로 MPA가 있는데 SPA는 Single Page Application으로 한 개의 페이지로 구성된 어플리케이션, MPA는 Multiple Page Application으로 여러개의 페이지로 구성된 어플리케이션을 의미한다.

 

SPA는 웹 어플리케이션에 필요한 모든 리소스를 한번에 다운로드해서 초기 세팅 시간이 오래걸리지만, 하나의 페이지 안에서 이동을 할 때 페이지가 빨리빨리 전환된다는 장점이 있고 MPA는 그때그때 서버에서 필요한 리소스를 가져와 페이지를 렌더링하기 때문에 깜빡임 현상이 일어날 수 있다는 단점이 있지만 필요한 리소스들이 서버에 저장되어있어 검색엔진에 잘 잡힌다는 장점이 있다. 내가 이번주에 개발한 페이지는 SPA이다!!

 

3. 상태관리란?

상태란, 컴포넌트의 변경 가능한 데이터 저장소인데 이런 상태를 관리하기 위해서 context API, redux, recoil 등을 사용한다. 나는 그 중에서 recoil을 사용해서 상태관리를 하게 되었다.

 

어려웠던 점

이번주에서 가장 힘들었던 건... 채팅방에서 input을 받았을 때 recoil을 이용해 store에 저장된 채팅 리스트를 리뉴얼 하는 작업이었다.

 

내 채팅 json은 chatRoom 이라는 상대 user id에 따라 배정되는 roomId를 기준으로 

 

/interface/chatRoom.tsx

export interface chatRoom {
  roomId : number,
  chat: chat[]
}

아래와 같은 chat 메세지들이 들어있는 구조이다.

 

/interface/chat.tsx

export interface chat {
  talker : number,
  listener: number,
  chat: string,
}

 

위 타입을 기준으로 한 메세지 json 파일은 다음과 같다.

 

/assets/chatInfo.json

[
  { 
    "roomId":0,
    "chat": [
      {"talker":5, "listener":0, "chat": "네가 참 궁금해"},
      {"talker":0, "listener":5, "chat": "그건 너도 마찬가지"},
      {"talker":5, "listener":0, "chat": "이거면 충분해"},
      {"talker":0, "listener":5, "chat": "쫓고 쫓는 이런 놀이"}
    ]
  },
  { 
    "roomId":1,
    "chat": [
      {"talker":5, "listener":1, "chat": "You and me"},
      {"talker":1, "listener":5, "chat": "내 맘이 보이지"},
      {"talker":5, "listener":1, "chat": "한참을 쳐다봐"},
      {"talker":1, "listener":5, "chat": "가까이 다가가"}
    ]
  },
  { 
    "roomId":2,
    "chat": [
      {"talker":5, "listener":2, "chat": "처음 본 순간부터 이끌린"},
      {"talker":2, "listener":5, "chat": "오묘한 색의 빛 속"},
      {"talker":5, "listener":2, "chat": "기다린 듯 now I'm burning"},
      {"talker":2, "listener":5, "chat": "눈부시게 shine"}
    ]
  },
  { 
    "roomId":3,
    "chat": [
      {"talker":5, "listener":3, "chat": "감춰둔 본능을 이끄는 Light"},
      {"talker":3, "listener":5, "chat": "한입에 삼켜 널 Delicious"},
      {"talker":5, "listener":3, "chat": "아찔한 미끼로 Hook up"},
      {"talker":3, "listener":5, "chat": "관심을 먹고 Growing up"}
    ]
  },
  { 
    "roomId":4,
    "chat": [
      {"talker":5, "listener":4, "chat": "실례합니다 여기 계신 모두"},
      {"talker":4, "listener":5, "chat": "야한 작품을 기대하셨다면"},
      {"talker":5, "listener":4, "chat": "Oh I'm sorry"},
      {"talker":4, "listener":5, "chat": "그딴 건 없어요"}
    ]
  }
]

여기서 나는, 유저가 채팅을 치면, talker와 listener id를 각각 계산해서 

 

newChat = {
        talker: talker,
        listener: listener,
        chat: value,
      };

라는 newChat을 스토어에 저장한 chatInfo에 추가해주어야하는 상황이었다.

여기서 문제점은, 그냥 냅다 chatInfo를 변경하면 안되고 chatInfo[roomId].chat까지 구조를 타고타고 들어가서 변경해야한다는 것이었다... 맨 처음에는 냅다 chatInfo[roomId].chat = chatInfo[roomId].chat.concat(newChat) 과 같이 리스트를 직접 추가하는 방법을 시도했었는데, 에러화면이 나에게 직접 변경은 불가능 어쩌고 저쩌고..를 시전했다.

 

그래서 chatInfo의 값을 복사한 새로운 객체를 만들어서, 해당 객체를 타고타고 들어가서 새로운 채팅을 추가해주고,

다시 이걸 저장되어있는 chatInfo에 반영하는.. 뭐 그런 개고생을 했다.

말로는 이렇게 간단하지만 이 간단한 걸 한 세시간 붙잡고 있었다. 오류 죽어...

그래서 완성한 코드 중 주요 부분은 다음과 같다.

 

const active = useRecoilValue(activeId);
  const [chats, setChats] = useRecoilState(chatList);
  const [newChatList, setChat] = useState(chats[roomId].chat);
  
  // 후에 스토어에 저장된 chatList를 갱신해줄 채팅룸 리스트
  let newChatInfo = [
    {"roomId":0, "chat": []},
    {"roomId":1, "chat": []},
    {"roomId":2, "chat": []},
    {"roomId":3, "chat": []},
    {"roomId":4, "chat": []},
  ] as chatRoom[];

const plusList = (value: string) => {
    if (value.trim()) {
      let newChat: chat;
      
      // 새로 만든 채팅값
      newChat = {
        talker: talker,
        listener: listener,
        chat: value,
      };
      
      // 내가 받은 채팅값을 후에 갱신에 사용할 리스트에 추가해준다.
      setChat(newChatList.concat(newChat));
      
      // 지금 들어와있는 room이 아닌 방들은 기존 방의 리스트를 그대로 가져오고
      // 현재 방 리스트만 내가 만든 채팅 리스트 값으로 갱신한다.
      for(let i=0 ; i<5 ; i++){
        if(i!=roomId){
          newChatInfo[i].chat=chats[i].chat;
        } else {
          newChatInfo[i].chat = newChatList.concat(newChat);
        }
      }
      
      // 내가 만든 newChatInfo로 store에 저장된 리스트 값을 갱신해준다!!!!!!
      setChats(newChatInfo);
    }
  };

 

배포한 링크는 다음과 같다!!

https://jieun-message.vercel.app/

 

React App

 

jieun-message.vercel.app

작고 소중한 나의 채팅 어플리케이션...

Comments