[항해99 취업 리부트 코스] 프로젝트 2주차 WIL

김가희·2024년 5월 2일
0
post-thumbnail

- 이번 주 항해 취업 리부트코스에서 내가 구현한 기능은 무엇인가요?
커머스라는 주제를 가지고 프로젝트를 하게 되었다. 나는 그 중 festa! 같은 컨퍼런스 및 이벤트 티켓 예약 플랫폼을 만들기로 하였다.

  • 이벤트 목록 가져오기
  • 최신 순/인기 순 정렬 기능
  • 카테고리/가격 필터링 기능
  • 검색 기능
  • PreFethcing 적용하여 이벤트 상세 페이지 구현
  • 이벤트 찜 등록/삭제 기능
  • 장바구니 CRUD

- 해당 기능을 구현하기 위해, 어떤 기술적 의사결정을 거쳤나요?
내가 무한 스크롤 구현 시 가장 중점을 두는 부분은 로딩 상태 관리와 성능 최적화이다.
로딩 상태 관리를 중요하게 생각하는 이유는 UX 때문인데, 나는 이번 프로젝트에서 로딩 스피너 같은 시각적 요소를 통해 사용자에게 로딩 중임을 명확하게 알려 주었다.
무한 스크롤을 구현하면 성능 최적화는 필수라고 생각한다. 나는 서버 측에서 페이지네이션 기법으로 데이터를 전달하게 하여 네트워크 자원 낭비를 막으려고 하였고, 디바운싱이나 쓰로틀링 같은 기술로 불필요한 데이터/DOM 조작 연산을 줄여 주어 브라우저 성능을 개선할 수 있게 노력하였다.

  • [무한 스크롤]을 구현하기 위해 고민한 기술의 종류들에는 무엇이 있나요? ex) A, B, C 중 B 선택
    • A: IntersectionObserver
    • B: react-intersection-observer 라이브러리 <- 선택
  • 위 기술들별로 각각의 장단점이 있다면 무엇인가요?
방법장점단점
IntersectionObserver표준 API: IntersectionObserver는 브라우저에서 제공하는 웹 표준 API이므로, 별도의 라이브러리 설치가 필요 없음.API 사용법이 복잡하고 초기 설정이 어려울 수 있음. 옵저버를 만들고, 관찰을 시작하며, 필요하지 않을 때는 해제하는 등의 과정을 직접 관리해야 함.
react-intersection-observer 라이브러리React 컴포넌트로 쉽게 통합할 수 있으며, 훅을 통해 간단하게 사용할 수 있음. 컴포넌트 마운트 시 자동으로 관찰을 시작하고, 언마운트 시 자동으로 정리함.외부 라이브러리를 프로젝트에 추가해야 하므로, 프로젝트의 크기가 증가할 수 있음. 내부적으로 구현된 방식에 따라 사용해야 하므로, IntersectionObserver API를 직접 사용할 때보다 유연성이 떨어질 수 있음.

- 이번 주 겪은 트러블 슈팅이 있다면 무엇인가요?

가격(유료/무료)을 기준으로 필터링 하려고 했다. (썸네일 참고)
근데 배열의 각 객체의 특정 필드(예: price)에 대해 조건을 설정하는 것은 Firestore의 기본 쿼리 기능으로는 직접적으로 수행할 수 없다고 한다.

위 이미지가 현재 내 티켓 필드인데 해결 방법으로는 두 가지가 생각났다.

  1. 클라이언트 측에서 데이터를 필터링 하는 방법: Firestore에서 모든 이벤트를 가져온 후, 클라이언트 측에서 price 조건에 맞게 필터링하는 것
  2. 데이터 구조를 변경하는 방법: 각 이벤트에 대해 "최소 가격" 필드를 추가하는 방법

1은 구현은 번거롭지 않고, 구현이 어렵진 않지만, 데이터 양이 많아지면 성능에 문제가 생길 것 같다는 생각이 들었다. 그래서 2로 결정.

export const getAllEvents = async ({
  pageParam = null,
  sort = '최신순',
  category = [],
  price = '전체',
}: {
  pageParam: number | null;
  sort: '최신순' | '인기순';
  category: string[];
  price: PriceFilterType;
}) => {
  // 페이지당 아이템 수
  const PAGE_SIZE = 12;
  const eventsRef = collection(db, 'events');

  let q = query(eventsRef);

  // 카테고리 필터 적용
  if (category.length > 0) {
    q = query(q, where('category', 'in', category));
  }

  // 가격 필터 적용
  if (price !== '전체') {
    if (price === '무료') {
      // "무료"는 minPrice가 0원인 경우
      q = query(q, where('minPrice', '==', 0));
    } else if (price === '유료') {
      // "유료"는 minPrice가 0원 초과인 경우
      q = query(q, where('minPrice', '>', 0));
    }
  }

  // 정렬 옵션 적용
  if (sort === '최신순') {
    q = query(q, orderBy('eventCreationDate', 'desc'));
  } else if (sort === '인기순') {
    q = query(q, orderBy('likesCount', 'desc'));
  }

  // 페이징 처리
  if (pageParam) {
    q = query(q, startAfter(pageParam), limit(PAGE_SIZE));
  } else {
    q = query(q, limit(PAGE_SIZE));
  }

  const querySnapshot = await getDocs(q);
  const lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];

  const events = querySnapshot.docs.map(doc => ({
    uid: doc.id,
    ...(doc.data() as EventType),
    status: calculateEventStatus(doc.data() as EventType),
  }));

  return { events, lastVisible };
};


항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
#개발자포트폴리오 #개발자이력서 #개발자취업 #개발자취준 #코딩테스트 #항해99 #취리코 #취업리부트코스

0개의 댓글