- 프로젝트명 : BlueMoon
- 프로젝트 제작기간 : 2022.04.22 (금) ~ 2022.06.02 (목)
- 서비스 소개
- 음성으로 익명 다이어리를 작성하고, 댓글을 공유할 수 있습니다.
- 주요 기능
- webRTC, Recording API 를 이용한 음성 녹음 및 재생
- sockjs-client / Stompjs 를 활용한 실시간 채팅, 알림
- 개발 언어 : JavaScript
- 개발 라이브러리 : React.js
- 형상 관리 : git
- 협업 툴 : Notion, Slack, Figma
- 팀원 : 곽혜미, 이춘
- 담당영역
- 곽혜미: webRTC, Recording API, diary 관련 페이지, Intro, 메인, 로그인
- 이춘: webSocket(실시간 채팅, 실시간 알람), API 및 뷰(닉네임 설정, 마이페이지, 채팅리스트, 이벤트페이지),
-
webRTC
- 별 다른 소프트웨어 설치 없이 서비스 메인 기능인 실시간 음성 녹음 스트림을 제공받을 수 있고, javscript api로 제공되어 러닝커브가 낮았음
- mediaRecorder api에서 제공하는 녹음, 재생, 정지 등의 기본 기능이 서비스 메인 기능을 커버하기에 충분했음
-
sockjs-client (1.6.0) / stompjs (2.3.3)
-
WebSocket을 지원하지 않는 브라우저까지 지원함
-
사용법은 WebSocket과 유사
webSocketFactory와 유사한 SockJS object 생성 → 연결 시 connect → subscribe, send 등 메소드 사용 → 연결 종료 시 disconnect
-
-
react-query (3.38.0)
- mutation을 사용해 diary 작성, 댓글 등 CUD 작업에 대한 get 요청을 자동으로 fetching 하여 리덕스 및 state 사용을 줄이고 서버의 최신화 된 데이터를 보여주어 사용자 경험을 높일 수 있음
- loading, error 값들을 제공해주어 상태 파악이 용이하며, enabled, cache time 등의 옵션 설정으로 원하는 조건에 맞게 서버 데이터 컨트롤 할 수 있음
-
redux-toolkit (1.8.1)
- redux의 보일러 플레이트 작성을 간소화(action creator 생략)
- thunk, immer 기능이 내장되어 있어, 별도 설치하지 않아도 비동기 처리와 불변성 관리를 할 수 있었음
-
zustand (4.0.0)
- 전역 상태관리 라이브러리로 redux-toolkit 보다 더 가볍게 쓸 수 있는 라이브러리를 찾다가 채택
- 세팅 코드가 단 4줄밖에 안될정도로 간단하여, 카테고리바의 간단한 UI 상태관리에 사용
-
Eslint/prettier
- 프론트엔드 2명의 코드 스타일을 맞추고 단순 인덴테이션 차이로 인한 충돌 최소화를 위해 도입
- 세미콜론 및 double quotes 미 작성시 오류를 발생시켜 코드 스타일 일치화
-
react-responsive (9.0.0-beta.8)
- media-query로 반응형 웹을 구현하기 위해 사용
- 유저의 뷰 포트에 따라 모바일/PC 웹 뷰 보여줌
- router로 연결되는 페이지는 pages 폴더에 배치했습니다.
- api와 redux, component 모두 메인 기능으로 모듈을 쪼개서 각 폴더에서 관리했습니다.
- 중복되는 음성 녹음 코드들은 hooks으로 만들어 따로 뺐습니다.
- shared에는 공통으로 쓰는 react 컴포넌트들을 관리했습니다.
- utils 에는 공통으로 쓰는 함수이면서 react 컴포넌트가 아닌 파일들을 넣었습니다.
- 현상
- Header 컴포넌트에서 웹소켓을 구독, 내 게시물에 댓글이 달리면 알람 메시지를 받도록 해둠
- 구독한 웹소켓에서 댓글 알람 메시지가 중복으로 돌아와, 같은 메시지가 중복으로 리듀서에 추가되는 문제가 발생 (2~10번 이상)
- 원인
- 페이지를 이동할 때마다(컴포넌트 unmount 시) Header 컴포넌트에서 웹소켓 unsubscribe 처리를 하지 않아, 소켓 연결 수가 늘어남
- 해결
- 웹소켓이 연결되는 컴포넌트에 useEffect cleanup 함수로 웹소켓 disconnect 실행하여 연결을 해제
- 현상 : 소켓이 연결된 페이지가 리랜더링 될 때마다 SockJS client object 생성 시도 지속되며, 서버 다운 상황 발생
- 원인 : 페이지 컴포넌트 return 내에서 선언된 client object가 리랜더링 시마다 초기화되며, client object 생성 코드가 동작
- 해결
- client object 선언을 useEffect 에서 하고, useRef로 선언한 ref 객체에 client object 를 할당, ref 객체를 페이지 컴포넌트 return 에서 사용
- 때문에 컴포넌트의 리랜더링이 발생하더라도 client 객체가 계속해서 값을 유지하게 해서, 리랜더링 되는 상황을 방지 (생성한 client로 연결이 이루어지므로 연결을 유지하기 위해선 client가 유지되어야 한다고 생각)
- 현상: 각 댓글의 음성 녹음 play 버튼을 여러번 누르면 오디오가 여러개 생겨서 음성이 겹침
- 원인: 버튼을 누르는 타이밍에 audio 객체를 생성하니, 동일한 파일의 음성파일 객체가 계속 생겨나는 현상
- 해결: 댓글마다 객체를 두고 src에 서버에서 내려온 voiceUrl을 주어 play 버튼을 누르면 audio element를 useRef로 가져와 재생시킴
- 현상: 리프레시 토큰을 발급하는데 계속 만료된 토큰이라고 나오는 이슈
- 원인: 리프레시 토큰으로 새 액세스 토큰을 받아오는 동안 다른 요청들이 동시에 토큰 재발급을 요청해서 토큰이 여러게 발급되고, 유효하지 않은 토큰이 생김
- 해결: axios의 interceptor에서 리프레시 토큰을 요청하는 동안(bool으로 구분) 들어오는 요청을 서버에 보내지 않고 배열에 모으고, 토큰 발급이 끝나 header에 accessToken을 다시 세팅하면, 그 때 이전에 모아놨던 요청들을 유효한 토큰과 함께 서버에 보내는 것으로 처리