본문 바로가기

Frontend Study - 1/프로젝트 후기

Nextron 실시간 채팅 프로젝트 후기

Nextron (Next.js + electron)과 Firebase를 이용해서 실시간 채팅 프로그램을 만들어 보았다. 

 

목차

1. 프로젝트 소개

2. 프로젝트에서 맞닥뜨린 문제들

3. 최종 후기

 

 

1.  프로젝트 소개

기술 : Nextron (Next.js + electron), Typescript, Firebase, Redux

구성 : 로그인 / 회원가입, 유저목록, 실시간 개인대화, 실시간 그룹대화

 

1) 로그인 / 회원가입

 


- Firebase Authentication을 이용

- 회원가입, 로그인 요청 후 각각의 응답 값에 대한 핸들링 및 유저에게 알려줄 수 있게 구현

- 로그인 상태 값 Redux로 관리

- 모든 유저가 전체 유저리스트에 접근할 수 있도록 파이어베이스 auth database외 별도의 유저리스트 데이터베이스 추가 생성 

 -> 1:1 대화를 시작할 때, 전체 유저리스트에서 원하는 상대를 선택 후 대화를 시작할 수 있도록 했기 때문

 

 

 2) 유저목록

 


- 유저리스트 데이터를 getServerSideProps로 서버사이드 렌더링해서 가져올 수 있게 함

 -> build시 export 불가 문제로 클라이언트사이드 fetching으로 변경

- 가져온 데이터 중 본인 아이디는 리스트에서 제외시킴

- 대화 상대 검색기능 : 인풋 상태 값과 filter method 활용

- 대화하기를 누르면 바로 개인 대화창으로 넘어감

- 기존에 했던 대화가 있으면 해당 대화를 기존 데이터베이스에서 불러오고, 없으면 상대방과의 새로운 개인 대화방을 데이터베이스에 추가

 

 

3) 개인대화

 

 
 

 

- 개인대화방 데이터베이스 새로 생성 시, 방 제목(id) 을 로그인 계정 + 상대방 계정 합친 값으로 설정

- 상대방 계정에서 이 개인 대화방을 찾을 때는 로그인해 있는 계정과 ,  상대방 계정이 바뀌기 때문에,

로그인계정 + 상대방계정 / 상대방계정 + 로그인계정 두가지 값을 차례대로 요청해서 있는 값으로 활성화

- 없으면 post를 통해 새로운 방 생성

- 메시지를 보내면 해당 방id 데이터베이스 밑으로 메시지 데이터가 추가됨

 



로그인 유저 aa@gmail.com의 개인채팅방 리스트
 로그인 유저 okok@gmail.com 의 개인채팅방 리스트

 

- 기존에 만들었던 대화방에 다시 입장하기 위해서 둘의 채팅방 데이터베이스 외, 각 유저별 채팅방 '리스트'가 필요했음

- 채팅방을 만들면서 로그인한 유저의 채팅방 리스트 데이터에 상대방 계정을 추가

- 동시의 상대방 계정의 채팅방 리스트에도 현재 로그인한 유저를 추가함

- 서로 해당 채팅방 리스트에서 타겟을 클릭했을 때 타겟의 id를 통해 대화방으로 들어갈 수 있게함

 


 

- 실시간 채팅 : Firebase Realtime Database를 이용

- 'onValue'라는 live 데이터 변화를 체크해주는 Firebase method와 useState 활용

 

 

 

4) 그룹채팅

 


 

 

- 방을 만들어서 초대하는 방식으로 그룹채팅 구현

- 방을 만들면 방 제목 (id) 값으로 그룹 채팅 데이터베이스가 만들어 지고,

- 개인 별 그룹 채팅 리스트에도 해당 방 제목 데이터가 들어감

 


 

- 초대하기를 누르면 회원 가입시 만들어 두었던 userlist 데이터베이스에서 해당 계정을 찾음

- 있는 계정이라면 채팅방id 데이터베이스의 member 값에 해당 계정을 추가

- 그리고 초대할 대상의 계정, 타켓 유저의 그룹 채팅방 리스트 데이터베이스에도 이 채팅방 id를 추가

- userlist에서 계정 찾기에 실패하거나, 이미 채팅방에 추가된 계정이라면 추가가 불가하게 구현

 

 

초대되었던 상대방 계정 (okok@gmail.com) 에서의 그룹채팅방 화면

 

 

- 그룹채팅방 id가 고유해야 하기 때문에 동일 이름으로 방을 만들 수 없게 구현

 

 

 

2.  프로젝트에서 맞닥뜨린 문제들

 

1) Electron과 next.js의 getServerSideProps

 

- electron으로 데스크탑 어플레케이션을 제작할 때 build시 export 과정이 수반 됨

- 동적데이터(로그인 유저 별 채팅 내용)가 포함되어 있고, 서버 사이드렌더링을 활용하기 위해 getServeSideProps로 데이터를 가져오는 것으로 모든 페이지를 구성했는데, 해당 함수는 export가 불가능했음.

- getServerSideProps의 라이프사이클이 export와 호환되지 않는다고 함 (* 공식문서 : https://nextjs.org/docs/messages/gssp-export)

 

해결 : 클라이언트 사이드 페칭으로 모두 수정 -> build 가능해짐

 

 

2) Next.js의 api Route 사용 문제

 

- 위와 마찬가지로 내부 서버를 통해 진행되는 사항이기 때문에, api Route를 사용한 모든 통신이 올바르게 동작하지 않음

 

해결 : 클라이언트 사이드 페칭으로 모두 수정

 

 

3) Live 채팅 구현과 firebase CRUD methods

 

- firebase Realtime Database 공식문서에 데이터 쓰기의 경우 set()을 이용하라고 되어있음.

- set이 POST의 개념인 줄 알았으나 PUT의 개념. 즉 모든 데이터를 대체.

- 메시지를 입력하고 데이터를 넘겼을 때, onValue 메소드에 들어오는 값이 하나의 메시지 데이터였기 때문에,

onValue를 하나의 메시지만 뽑아서 나타내주는 method로 착각

 

해결 : POST 개념의 method인 push메소드로 변환해서 구현

 

 

4) Database 구조, 데이터 모델링 작업

 

- 처음에 채팅방 내부 메시지 데이터와, 유저별 채팅방 리스트 데이터를 하나로 관리하려고 시도.

- 구조가 매우 복잡해지고, 채팅방 리스트만 필요한 페이지에서 각 채팅방에 있는 모든 데이터들 까지 다 불러오게 되었음

 

해결 : 데이터를 분리하여 관리

- 예전 팀 프로젝트를 할 때 백엔드 파트 분들이 모델링 짜는데 왜 그렇게 시간을 많이 쓰는지 이해하게 됨..

 

 

 

그 밖의 잔잔하지만 고생한 것들

- getServerSideProps안에서 api Route를 통해 통신을 하려고 했다. 이미 서버통신을 하고 있는 곳에서 한번 더 서버를 통해 통신 하려고 했던 것.

* 공식문서

더보기

getServerSideProps or API Routes

It can be tempting to reach for an API Route when you want to fetch data from the server, then call that API route from getServerSideProps. This is an unnecessary and inefficient approach, as it will cause an extra request to be made due to both getServerSideProps and API Routes running on the server.

 

Take the following example. An API route is used to fetch some data from a CMS. That API route is then called directly from getServerSideProps. This produces an additional call, reducing performance. Instead, directly import the logic used inside your API Route into getServerSideProps. This could mean calling a CMS, database, or other API directly from inside getServerSideProps.

 

- 컴포넌트에 async 씌워져있음

Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

이 에러와 한참 싸웠는데, 컴포넌트에 async가 씌워져 있었다. .

 

 

3. 최종 후기

 

기획단계는 역시나 중요했다. 

 

막연하게 live chatting = socket i.o 라고 알고 있어서 socket i.o로 한참 하다가 뒤늦게 firebase realtime database를 통해 라이브 채팅 구현이 가능하다는 것을 알게 되었다. (기업 과제 자체가 nextron + firebase를 통한 live채팅 구현이었음)

 

그... 이름을 통해 유추할 수 도 있었을텐데, real time 이잖아..? ㅠ

 

그리고 getServerSideProps 함수가 export 불가했던 부분.

사실 맞아 보기전까지는 몰랐을 거 같은 사실이지만 그래도 먼저 알았다면 시간을 많이 절약할 수 있었을 것 같다. 

데이터베이스의 구조도 마찬가지로 처음부터 모델링을 잘 했다면..

 

기획단계에서 제대로 구상 했다면 피해갈 수 있었을 문제들을,

구현을 한참 하다가 중간에 발견하여 작업했던 것을 되돌려야 하는 경우가 많았던 것 같다.

 

'일단 시작해보자' 하면서 코드부터 입력해 나가는 것이 아니라,

'일단 시작해보자' 하면서 기획 다운 기획을 !