Team-Project ( popstore-community ) 회고록

이준석·2023년 6월 20일
0

Project

목록 보기
7/7
post-thumbnail

시연영상

- 검색, 필터링 기능


- 글쓰기, 댓글 쓰기

1. 프로젝트 소개

  • 팝업스토어 커뮤니티
    전국에 열리는 팝업스토어들의 정보를 모아 확인할 수 있으며,
    커뮤니티의 기능으로 팝업스토어 관련 소통 활성화를 목적으로 가진 웹 프로젝트
  • 프로젝트 기능
    • 지도를 통해 가까운 팝업스토어를 찾을 수 있고,
    • 필터링을 통해 원하는 팝업스토어만 골라 볼 수 있으며,
    • 커뮤니티페이지에서 같은 관심을 가진 사람들끼리 소통할 수 있는 웹 서비스 제작 프로젝트 입니다.
  • 본인 담당 부분
    • 커뮤니티 페이지 (게시판 목록)
      • 게시판 카테고리 별로 확인 (전체, 자유, 후기, 모집)
      • 팝업스토어 카테고리, 지역, 기간 등 필터링 기능
      • 게시글 검색 기능
      • 페이지네이션
    • 상세 게시글 페이지
      • 댓글, 대댓글 생성, 삭제
      • 게시글 좋아요, 싫어요 추가 또는 삭제
    • 글쓰기 페이지
      • 글 생성, 수정, 삭제
      • 후기, 모집 게시판 작성 시 해당 팝업스토어 선택
      • 후기 게시글 선택 시 평점 선택
      • 스토어 필터, 검색 기능

2. 프로젝트를 진행하며 어려웠거나 고민한 점

1. CRA가 아닌 Vite 사용

  • CRA는 JavaScript로 구성된 Webpack을 사용하는데 속도가 느린편이다.
  • 이를 해결하기 위해 Esbuild를 기반으로 만들어진 빌드툴인 Vite를 사용
    • Esbuild는 기존 번들러와 달리 자바스크립트(javascript)가 아니라 go언어로 작성이 되었다.
  • 그리고 Vite는 ESModule을 사용하여 빠른 개발 시간을 제공하며,
  • HMR(Hot Module Replacement)을 지원하여 코드 변경을 실시간으로 반영하여 빠른 개발 및 디버깅을 가능하게 한다.
    • HMR은 다른 모듈에 영향을 주지 않고 개발 중인 모듈만을 실시간으로 업데이트 해준다.

2. 상태관리 라이브러리 선택

팀원들 모두 상태관리 라이브러리를 사용해본 경험이 없어, 상태관리 라이브러리는 Redux-toolkit을 사용하기로 하였다.
Redux-toolkit은 Redux의 난이도를 상당히 낮춰주었다.
스토어 생성, 리듀서 작성, 불변성 업데이트 등 많은 것을 해주어 복잡성을 줄여준다.
너무 많은 것을 해주기에 추후 Redux-toolkit을 사용하지 않고, Redux로만 기능 구현해봐야겠다고 생각했다.


3. Redux-toolkit과 React-Qurey를 같이 사용한 이유

프로젝트의 첫 번째 목적은 성장이지만,
위와 같이 Redux-toolkit이 Redux의 난이도를 많이 낮춰주었다.
그렇기에 또 실무에 많이 사용하는 React Qurey를 배우면 좋을 것 같아
프로젝트에 적용하기로 하였다.
하지만 급하게 할려고 하다보니 제대로 사용하지 못해 아쉬움이 남아 프로젝트가 끝난 뒤 개인적으로 API 통신 부분을 React Qurey로 리펙토링을 진행하며 학습하였다.


4. 프로젝트의 폴더 구조

그리고 Redux-toolkit을 사용하면 Duks패턴을 많이 사용한다고 한다.
프레젠테이셔널 컴포넌트(UI담당)와 컨테이너 컴포넌트(상태관리 담당)로 관심사의 분리가 이루어져 UI를 작성할 때 좀 더 집중할 수 있다는 장점 있다.
프로젝트에 적용하면 좋을 것 같아 팀원들에게 의견을 내었다.
그리고 코치님에게 여쭤보니 현재 현업에서는 많이 사용하지 않는 패턴이지만, 학습하기엔 괜찮다고 하셔서 사용을 결정했다.


5. 서버와의 통신 횟수 줄이기

  • 게시글의 좋아요, 싫어요 버튼을 누르기 위해 3번의 서버와의 통신이 필요했다.
    1. 로그인중인 user의 정보 요청
    2. 게시글의 정보 요청 (좋아요 or 싫어요 누른 user 정보의 배열)
    3. 2번에서 1번 탐색 후 없다면 증가 요청, 있다면 삭제 요청

    개선 방법으로 요청으로 줄일 수 있다고 생각했다.
    처음 uesrId를 얻기 위해 user 정보를 요청하고,
    userId를 body에 담아 보내면 백엔드에서 직접 배열을 탐색하고 없다면 증가, 있다면 삭제하도록 하면 서버와의 통신이 2번으로
    줄일 수 있을 거라 생각해 백엔드 팀원에게 해당 내용을 전달하였고, 적용되어 서버와의 통신을 줄였다.

  • 같은 맥락으로 게시글 수정, 삭제 부분에서도 userId 비교 부분을 백엔드에서 담당하여 서버 통신 횟수를 줄였다.
  • 그리고 나중에 로그인한 user정보를 전역상태로 관리하게 되어 1번의 통신으로 줄여졌다.

6. 불필요한 데이터 요청

처음 게시글을 설계할 때, 게시글데이터에 comments데이터까지 populate하여 한 번의 요청으로 해결하려 했다.

Feed(게시글) 스키마
- title: string
- author: Types.ObjectId <User>
- board: string
- content: string
- images: string[]
- store_id?: Types.ObjectId <Store>
- ratings?: number
- likes: Types.ObjectId[] <User[]>
- reports: Types.ObjectId[] <User[]>
- comments: Types.ObjectId[] <Comment[]>
- views: number
Comment(댓글) 스키마
- author: Types.ObjectId <User>
- content: string
- parent: {
		type: string
		id: Types.ObjectId <Feed | Comment>
  }
- ancestor?: {
		type: string
		id: Types.ObjectId <Feed>
  }
- recomments: Types.ObjectId[] <Comment>

하지만 해당 설계를 변경해야겠다고 생각했다.

  1. 한 번의 요청이 무거워진다면, 화면에 렌더링될 때까지 유저는 그저 기다려야 한다.
  2. 댓글의 작성으로 업데이트할 때고 게시글 전체 받아 업데이트 해야한다.

위와 같은 이유로 feed에서 comments를 populate를 하지않고, 요청을 나눠 2번나누어 요청하는 것으로 해결했다.


7. 게시글쓰기 중 화면을 벗어난다면?

게시글을 작성하다가 글쓰기 페이지를 뒤로가기 버튼이나, 로고를 버튼을 눌러 벗어난다면 작성 내용은 어떻게 관리하는 게 좋을까?

두가지 관점에서 생각해 볼 수 있다.

  • 글을 쓰다가 작성을 멈추고 싶어서 일부러 벗어난 경우 (글의 내용이 없어져야 함)
  • 실수로 벗어난 경우 (글의 내용이 남아져 있어야 함)

그러다 react-router-dom에 prompt라는 컴포넌트를 알게되었다.

<Prompt
  when={shouldConfirm}
  message="Are you sure you want to leave?"
/>

porompt는 내가 지정한 페이지이동 뿐 아니라 페이지이동을 감지하고, 한번 더 확인하므로 위의 문제를 해결할 수 있다고 생각했다.
react-router-dom v6 부터 prompt컴포넌트 기능의 불안정으로 아직 출시되지 않았다고 한다. ㅠ
그렇게 다른 방법으로는 localStorage에 내용을 저장하는 방법을 알게되었는데,
게시글에 업로드 이미지를 base64형태로 받기 때문에 어려운 상황이었다.

그러던 중 useEffect의 cleanUp함수를 사용을 떠올렸다.
어차피 이 페이지를 떠난다는 건 컴포넌트들도 사라지는 의미이기 때문에 내가 지정한 취소버튼을 통한 페이지이동 뿐 아니라 페이지를 벗어날 때도 똑같이 처리 할 수 있다.

실수로 페이지를 벗었을 때에 대한 제어가 안되어 아쉽지만, 내용이 남아있는 게 더 사용자 경험에서 떨어진다고 생각해 페이지 이동 시 작성내용 초기화가 되도록 하여 통일성을 만들었다.


7. useMemo, useCallback을 잘사용하는 것

게시글 리스트들을 서버에서 받아오고 데이터를 useMemo로 memoization했다.
해당 리스트에는 아이템마다 이미지가 포함될 수도 있는데, 아이템의 갯수가 많아진다면 데이터가 굉장히 무거워질 것이라 생각했다.
다른 컴포넌트로 인한 렌더링으로 할당이 반복된다면 성능저하를 가져올 수 있다 생각해 useMemo를 사용했다.

  • memoization은 오히려 컴포넌트의 성능 저하를 가져올 수 있으므로 주의가 필요하다.

3. Troubleshoot

1. 한글 입력시 keydown 이벤트 중복 발생 현상

일부 팀원의 환경에서 엔터로 댓글 입력 시 API요청이 2번씩 들어가는 현상이 발생하였다.
하지만, 이러한 문제는 크롬 브라우저에서 한글을 사용하는 경우에만 문제가 발생한다. (영어로 입력하면 키 이벤트가 중복으로 발생하지 않음)

원인

  • IME composition = 한글, 일본어, 중국어 등을 변환하는 과정(composition)에서 keydown 이벤트는 OS 뿐만 아니라 브라우저에서도 처리되기 때문에 중복 발생된다.
  • JavaScript의 keyboard event 객체에 isComposing이라는 메소드가 있어 해당 메소드를 이용해 해결 가능
      const keyboardEventHandler = (event) => {
       if(event.isComposing) return;
        // ... 나머지 키보드 이벤트
      }
  • 하지만 React의 keyboard event엔 isComposing 이라는 메소드가 없다.
    • !! 추가
      프로젝트가 끝난 후에도 더 나은 코드로 남기고 싶어 찾아보다
      nativeEvent엔 isComposing이 포함되어 있어 사용해서 문제 해결이 가능하다.
    onKeyDown={(e) => {
         if (e.key === 'Enter' && e.nativeEvent.isComposing === false) {
             RegisterComment();
         }
     }}
  • React에서 composition event를 별도로 제공
      onCompositionStart={() => setIsComposing(true)}
      onCompositionEnd={() => setIsComposing(false)}
      onKeyUp={(e) => {
        if (isComposing) return;
        if (e.key === 'Enter') {
          RegisterComment();
        }
  • 하지만 기능이 제대로 되지 않아, 시간 부족으로 일단 keypress로 변경하여 임시로 조치
  • keypress의 사용은 지양된다. (Deprecated)
    • 대부분의 브라우저에서는 keydown 이벤트와 keyup 이벤트를 사용하는 것을 권장하고 있다.
    • ASCII 문자에 대한 키 코드를 반환하며, 특수 문자나 조합된 키에 대한 정보를 제공하지 않는다.

4. 프로젝트(협업) 후기

첫 번째 프로젝트보다 인원도 많아졌고, 그래도 경험은 경험이였는지
조금 더 수월하게 진행되었다 생각한다.
리액트와 리덕스를 사용하며, 상태관리 집중화가 왜 생겼는지 느낄 수 있었다.
개인 프로젝트보다 규모가 커지고, 페이지도 많아지다 보니 상태관리 집중화가 되어 관리하기에 편했다.
하지만 너무 리덕스에 의존하여 대부분의 상태들이 store에 몰린 것 같다.
store에 가야할 상태와 굳이 가지 않아도 될 상태를 구분할 수 있는 개념을 익혀야겠다.
그리고 라이브러리를 쓰기 위해서도 정확히 알아야 잘 쓸 수 있다고 생각이 들어 공부를 하면 할 수록 배울 것이 많다고 느낀다.

0개의 댓글