wanted preonboarding internship 2주차 - 여행 상품 리스트 및 장바구니 사이트

박준수·2023년 4월 19일
0

프로젝트의 주제

  • 여행 상품 리스트를 보고 장바구니에 저장할 수 있는 사이트 구현

프로젝트의 요구사항

  • 목데이터를 사용해서 과제를 진행
  • 별도의 디자인 명세는 주어지지 않는다.
  • 요구사항을 충족시키는 선에서 지원자의 판단하에 UI를 구성해주면 된다.
  • 필수 기술: chakra-ui, (emotion)
    • 필수기능에 부합하는 디자인을 chakra-ui를 이용하여 구현해주세요
    • chakra-ui로 할 수 없거나 부가적인 스타일링은 emotion을 이용해 주세요

프로젝트 진행 전 신경쓴 점

기술스택 논의

  • 프로젝트에 들어가기에 앞서 각각의 기술스택들은 어떤 것들이 있는지
  • 그리고 그것들중 왜 이것을 사용했는지를 문서화하여 정리했다.
  • 이를 통해 기술을 도입할 때 그리고 사용할 때 중요한 핵심인 “왜 사용하는가?”를 모두가 이해하고 진행하기에 기술스택을 사용함에 있어 어려움이 감소되었다.
    • 이 과정에서 기술스택이 꼭 유행하는 것이 아닌 주어진 프로젝트에 맞는 기술스택을 사용해야 한다는 것을 다시금 느꼈다.

요구사항 분석

  • 프로젝트에 들어가기에 앞서 요구사항들을 분석했다.
  • 무턱대고 개발하는 것이 아닌 모두가 머리를 모아 먼저 로직을 정리해보는 시간을 갖었다.
  • 이를 통해 팀원들이 코드리뷰에서 들어가는 시간을 조금이나마 절약할 수 있었다.

프로젝트에서 도입된 주요 기술

컴포넌트 구조 및 폴더 구조

src
 ┣ 📂components
 ┃ ┣ 📂common
 ┃ ┣ 📂OrderSummary
 ┃ ┣ 📂Reservation
 ┃ ┗ 📂Travel
 ┣ 📂constants
 ┣ 📂hooks
 ┣ 📂mocks
 ┣ 📂pages
 ┣ 📂providers
 ┃ ┣ 📂Reservation
 ┃ ┣ 📂Travel
 ┣ 📂router
 ┃ ┣ 📂loaders
 ┣ 📂types
 ┣ 📂utils
 ┣ 📜App.tsx
 ┣ 📜main.tsx
 ┗ 📜vite-env.d.ts

Design Pattern

  • 우선 페이지를 두가지로 나누었다.
    • 여행 상품 리스트를 볼 수 있는 Main페이지
    • 저장한 여행아이템을 확인할 수 있는 Reservations페이지
  • Main페이지는 다시 Filter와 TravelItemBox로 나뉜다.
    • Filter는 다이어그램에는 안나왔지만 자식 컴포넌트로 FilterCheckboxGroup을 하나 뒀다.
    • FilterCheckboxGroup는 chakra UI로만 구성되어져 있다.
    • 이 chakra에서 제공하는 MenuItemOption이 check되면 MenuOptionGroup의 onChange에 바인딩된 함수를 통해 filter를 구현한다.
  • TravelItemBox는 TravelItem으로 구성되어지고
  • TravelItem은 ReservationButton을 자식으로 갖는다.
    • 또한 QuantityButton도 자식으로 갖는데 이 버튼은 장바구니에서도 쓰이므로 공용컴포넌트에 넣어 재사용성을 높인다.
  • Reservations페이지는 ReservationBox와 OrderSummary로
  • ReservationBox는 ReservationItem으로
  • ReservationItem은 QuantityButton과 DeleteButton으로 나뉘는데
    • 이때 이 DeleteButton은 나중에 또 쓰일 수 있으므로 common 폴더에 넣어 놓는다.
    • QuantityButton은 Main에서 쓰인 바로 그 버튼이다.
  • 각 컴포넌트의 구성을 보면 작은 컴포넌트들이 모여 하나의 컴포넌트를 이루며 그 컴포넌트가 더 큰 컴포넌트를 구성해나아가는 것을 볼 수 있다.

hooks

  • 비즈니스로직들을 따로 hook으로 빼서 관심사분리를 하였다.
  • Providers를 통해 전역적으로 context에 있는 state들을 props drilling 걱정없이 사용할 수 있게 하였다.

다중 필터링 기능 구현

  • 장소 필터와 가격 필터가 혼합되어 있는 다중필터링을 구현해야한다.
  • 설계의 주안점은 다음과 같다.
    • 우선 필터 자체의 기능만을 따로 filter함수로 만들고 utils로 빼놔서 추상화를 해놓는다.
      • 이를 통해 관심사를 분리하고 유지보수를 쉽게 한다.
      • 필터기능만 있기에 필터가 하나만 있을 때 두 개 있을 때 아예 없을 때 등등의 조건들을 비교적 쉽게 다룰 수 있다.
      • filter함수에서 return되는 filteredData가 우리가 렌더링하는 item 목록이다.
    • 필터가 더 늘어나는것을 대비하여 전역적으로 필터조건과 그 상태를 다루는 Reducer를 만든다.
      • 이를 통해 필터가 더 늘어나더라도 빠르게 확장을 할 수 있다.
    • Filter컴포넌트에서 필터링이 된 데이터의 상태를 변경시키고, 이 데이터를 가지고 TravelItemBox컴포넌트에서 리렌더링을 해야하기 때문에 멀리 떨어진 컴포넌트에서도 상태를 공유할 수 있도록 Context API를 사용한다.

장바구니 기능 - localStorage사용

  • 이 부분은 내가 처음에 만들때 실수를 했던 부분인데
    • 나의 경우 localstorage를 진짜 저장소처럼 사용하여
    • 장바구니를 만들때 +버튼을 누르면 localstorage의 숫자가 올라가고
    • 이 localstorage의 데이터를 기반으로 다시 렌더링을 하는 방식을 사용했다.
    • 지금 생각하면 왜 그랬는지, 무슨 생각으로 그랬는지 모르겠다..
  • 이 장바구니의 localstorage방법은 그냥 저장을 하고 Reservations 최상위 부모페이지에서 한 번만 그냥 함수로 불러들이는 거다.
  • 그리고 렌더링할때는 기존의 방식처럼 context를 사용해 전역적으로 수량 상태를 관리하면 된다.
    • 이렇게 하면 유저가 새로고침했을 때만 localstorage를 반영하여 값이 계속 저장되게 할 수 있다.
    • 물론 context에서 꾸준히 localstorage에서 set하는 함수를 적용해야한다.
    • 즉, context와 localstorage를 계속해서 update하되 렌더링은 context에 있는 것을 하고
    • useEffect를 이용해 리렌더링시에는 localstorage에 있는 데이터를 context로 업데이트하면 된다.

context API를 이용하여 props drilling 해결

  • QuantityButton 컴포넌트에서 수량을 변경하는 이벤트가 발생하여 상태를 변경시킬 때, 멀리 떨어져 있는 컴포넌트인 OrderSummary가 리렌더링 되어야 하기 때문에 Context API를 활용했다.
  • ReservationProvider를 구현하였고, Reservations 페이지의 하위 컴포넌트로 state와 dispatch의 스코프를 한정했다.
  • ReservationItem 컴포넌트에서는 dispatch 함수를 호출하여 수량 변경 버튼을 클릭하면 reducer를 통해 상태를 변경시킬 수 있게 됩니다. 그러면 OrderSummary 컴포넌트가 리렌더링되며 상품의 총 수량과 총 금액을 업데이트 할 수 있다.

끝으로

  • 이번 과제를 하면서 필터링이라는 로직에 대해 깊게 생각해보는 경험을 했다.
  • 필요에 의해 라이브러리를 써야 하며 그래서 꼭 redux를 사용하지는 않아도 된다는 것을 알았다.
  • 컴포넌트 구조를 설계함에 있어 좀 더 꼼꼼한 설계와 더불어 단단한 이해를 통해 구조가 중간에 바뀐다 할지라도 유동적으로 잘 바꿔야 한다는 것을 알았다.
profile
심플한 개발자를 향해 한걸음 더 (과거 블로그 : https://crablab.tistory.com/)

0개의 댓글