본문 바로가기
포스코x코딩온

[포스코x코딩온] 풀스택 부트캠프 15주차 정리 -2 3차 프로젝트 회고

by 김선지 2024. 2. 2.

01/31

에러 홈페이지를 따로 만들어야 한다.

server와 front가 같은 홈페이지 였을 때는 그냥 렌더해주면 편했지만, 리액트는 어떻게 하는지 모르겠다.

그래서 찾은 것이 react error boundaries였다. 에러를 띄우는 건 그냥 서버에서 json.status(500) , 이런식으로 쏴주면 되니까 상관 없긴 했다.

다만 react error boundaries를 이용하면 안되는 치명적인 이유가 있었다. 뭐 콘솔도 띄워주고 좋긴 한데. 사용자는 콘솔을 보면 안된다는 거였다.

 

react error boundaries를 이용해서 에러 페이지를 렌더한다면 그 전에 빨간 리액트 오류 화면이 먼저 나온다. 그렇게 된다면 사용자 입장에서 기분이 나쁠 수 있기 때문에 raise error가 아닌 redirect를 활용해서 해야겠다고 생각했다. 뭐 error.response.status를 이용해서 switch문을 돌리면 되니까 말이다.

그래서 재사용성을 늘리기 위해서 커스텀 훅을 만들었다. 실습시간에 했었는데도 좀 어려웠지만 어찌저찌 하다보니 만들 수 있었다. 다만... 중요한 건... 에러 페이지 디자인을 할 시간이 없다는 거다. 소싱해서 적당히 해결하자.

이런거

 

내가 만든 리액트용 에러처리 코드, 401에러 하려다가 사용자 입장에서는 redirect 해주는게 낫다고 생각했다. 진짜 401같은 에러는 403에서 처리한다.

 

그리고 처음에는 프로필 사진 경로를 allowNull로 정해놓기도 했고, 파일 이름이 전부 바뀌어버리니까 유저 테이블의 유저 아이디를 외래키로 받는 하나의 테이블로 설정했었는데, 이게 모든 채팅이나 포스트에 프로필 사진 경로가 필요해서 여간 귀찮은게 아니었다. 그래서 User 테이블에 병합했다.

 

- 에러 처리 핸들러를 구현하다가 적지 않은 페이지에서 401 status의 에러가 발생함을 알게 되었다. 찾아보니 그 원인은 내가 만든 getMyPage controller의 axios 요청을 다른 포스트 페이지에서 사용하고 있기 때문임을 알게 되었다.

팀원의 의도는 getMyPage함수에 params를 넣어서 어떻게 정보를 가져오려고 했던 것 같다.

다만 당연히 오류가 뜨는게, 나는 session.userid를 활용해서 mypage 데이터를 가져오게 설정했고, 만약 마이페이지에서 찾고자 하는 유저데이터와 session.userid가 다르면 401 에러를 띄웠기 때문이었다. 

 

즉, 자신의 유저 데이터만 fetch되어 원하는 결과를 얻지 못할 뿐더러 401에러까지 뜬다.

그래서 해당 요청을 보내는 경로를 이런 일이 있을 줄 알고 만들었던 다른 controller인 searchUser로 보냈고 거기에서 필요한 정보들을 json으로 쏴주었다. 그렇게 에러를 해결할 수 있었다.

 


02/01

follow와 following의 위치가 바뀌었다는 제보가 들어왔다. 이건 데이터베이스에서 userid, follow같은 것을 좀 헷갈리게 적어서 이런 일이 발생한 것 같기도 했다. 왜... 이렇게 만들었는지는 모르겠다. followingId, followedId 이렇게 했으면 좀 낫지 않았을까 싶다.

또한 모노 채팅방에서 필요한 정보를 가져다주는 백엔드 로직을 만들었다. 

다만 갑자기 요청사항이 많아졌다... (다음주 화요일 발푠데 말이지...)

1. 카카오톡 기능처럼 채팅방에서 내가 쓴 글을 아직 안 본 사람이 몇명인지 알려주었으면 좋겠다.

2. 룸 페이지에서는 내가 아직 안본 채팅의 수가 나왔으면 좋겠다.

3. 개인 채팅의 경우 룸에서 채팅이 가장 최신 순으로 나열되었으면 좋겠다.

 

굉장히 많은 고민 끝에 1번과 2번의 경우 하나의 테이블만 새로 만들면 해결될 거라고 생각했다.

그것은 바로 ChatCount 테이블로 구조는 다음과 같다.

roomNum은 room 테이블의 primary key인 roomNum과 1: N

chatIndex는 chat 테이블의 primary key인 chatIndex와 1: N

userid와 useridto는 이름에도 알 수 있듯이 user 테이블의 user와 1:N이다.

그리고 채팅 하나를 칠 때마다 다음과 같은 로직을 만들었다.

 

1. 채팅 목록을 돌아서 나를 제외한 유저 아이디를 모두 가져온다. (모든 유저는 처음 들어올때 어떤 말을 쓰기 때문에 채팅에 참여한 유저 수 = 방에 있는 유저수) 이다.

2. 아래 테이블에 create를 통해서 만든다. roomNum, chatIndex는 create를 통해서 받아온 변수이고, userid는 session값, useridTo는 여러개이다. (고로 나를 제외한 유저 아이디만큼의 iteration이 실행된다.)

3. 특정유저가 특정 방에서 fetch를 실행하면 (방에 들어오면) roomId (방 고유값)에 있는 useridTo (세션 아이디값)에 해당하는 데이터를 모두 destroy한다.

4. 다른 사람들에게 내가 봤다는 정보를 알려주기 위해 모든 사람들에게 fetch를 요청한다.

3번까지는 쉬웠는데 4번이 진짜 힘들었다.

그래서 웹소켓을 통해서 reload를 하게끔 만들었다. 

웹소켓에 참여한 모든 사용자에게 특정 이름으로 io.emit('reload')를 걸어서

클라이언트 측에서 socket.on('reload')를 받으면 데이터 목록을 다시금 fetch할 수 있게끔 만들었다.

그리고 이건 다른 사람이 fetch 했을때도, 다른 사람이 채팅을 썼을때도 마찬가지였다.

다른 사람이 채팅을 치는 건 쉬웠는데,

다른 사람이 fetch를 하는 건 감이 안잡혔다. 그래서 팀원분에게 이거 방법 없냐고 하니까, room에 입장했을 때 실행되는 함수를 만들어두셨다.

이게 개꿀이지. 여기다가 emit을 보냄으로써 결과적으로 성공했다.

 

sequelize 집계함수를 쓰다가 이상한 점을 발견했다.

이 두개는 성능면으로 비슷하다고 한다. 근데 전자는 별칭을 설정할 수 있고, 후자는 훨씬 가독성이 좋다.

웬만하면 후자로 고르지 않을까 싶다.

이건 findAll을 할때 중복을 제외하고 레코드를 가져오는 것.

 


02/02

어제 받았던 요청인 채팅 가장 최신순 나열 요청을 해결했다.

근데 그렇게 된다면 가장 최근 채팅 정보를 하나 가져와야 했다. 그렇게 정보를 하나 가져오고 다음 로직을 통해서 카카오톡처럼 수정할 수 있었다. 다른 사람의 fetch 요청은 어제 이미 emit 요청을 넣어놨기 때문에 안해도 됐다. 근데 이거 이상한게 저번에 post page를 담당했을 때는 b-a가 아니라 a-b로 했었는데 내림차순이 되었다. => 여기서 이상함을 눈치챘어야 했는데 그냥 두었다.

 

이게 진짜 말이 안되는거라서 한번 다 코드를 훑어봤다. 

알고보니까 프론트 담당하시는 분이 한번 reverse를 했음을 알게 되어서 안도의 한숨을 쉬었다. 역시 컴퓨터는 거짓말을 하지 않는다.

model: Chat 부분이 최근 채팅정보 하나를 가져오는 부분이다. attributes 해도 되지만. 귀찮았다
최근순으로 sorting, 지금은 일단 any로 해놨다. 귀찮은걸...

 

다른 주문이 들어왔다.

모노챗에서 참여한 사람이 아닌 현재 모노챗 페이지에 들어와 채팅을 치고 있는 사람의 수를 가져와달라는 요청과 채팅에 참여한 사람의 프사와 국적 정보를 가지고 와달라는 주문이었다.

음... 빡세다. 진짜 빡세다.

고민을 하다가 저번에 chatgpt한테 물어봤을 때 get(room)을 통해서 현재 있는 인원을 가지고 올 수 있다는 것을 떠올렸다.

그래서 joinRoom이 되었을 때, leaveRoom이 되었을 때 이벤트를 걸어서 get(room)을 통해서 해당 정보를 가져와서 db에 넣어주고 하면 되지 않을까 생각했다. 그래서 db를 또 하나 만들었다.

 

 

근데 이상한게 join room이 되었을 때는 이벤트가 발생하는데 leave room이 되었을때는 이벤트가 발생하지 않았다.

이건 자동으로 하는 게 아니라 커스텀으로 설정해줘야 하는 함수인 것 같다.

join room의 경우 어차피 룸에 들어가기 위해서는 join room emit을 통해서 보내줘야한다.

그치만 leave room의 경우 따로 emit을 설정하지 않았기 때문에 받지 못하는 것이었다.

근데... 어떻게 끄기 전에 해당 emit을 보내야할까...? 는 수업시간에 배웠던 lifeCycle을 이용하면 되겠다는 생각을 했다.

그래서 gpt한테 물어보니까 다음 답변이 왔다.

다만 이건 react의 lifeCycle이 아닌 브라우저 자체의 lifeCycle인 것 같다.

각설하고 여기서 쓸만한 건 쓰고 버릴만한 건 버리면 될거같다. 일단 confirmationMessage 같은 건 아무리 봐도 쓸데없는 코드다.

그래서 window.addEventListener('beforeunload', something) 부분만 가져갔다.

이러니까 페이지를 닫을 때도 잘 실행됨을 확인할 수 있었다.

 

다만 한가지 부분이 뒤로가기를 할 때는 이게 unload라고 보지 않는 것 같았다. 그래서 그냥 뒤로가기를 쓰지 않게 따로 뒤로가기 버튼을 만들기로 했다. 어차피 모바일이니까 상관 없을 것 같긴 하다. (근데 다른 분이 습관적으로 뒤로가기를 눌러서 그런가 현재 인원이 굉장히 많다.)

물론 leaveRoom을 받는 서버에서는 다시 한번 db에 명수를 넣는 함수를 넣어놨다.

get 함수는 set으로 가져오고 만약 size가 0이면 빈 set을 주는 것이 아니라 undefined를 반환한다.

그래서 그럴 경우 0으로 세팅하고 update를 다시 해준다.

 

이젠 env 파일과 mvc, 코드정리 좀 하고 서버에 올릴 준비를 해야겠다.