[3회차] 상품 페이지 - 컴포넌트 ‘잘’ 나누기

유현지·2022년 7월 28일
0

Numble

목록 보기
3/3

  • 쿠팡 상품 페이지를 구현
  • 공통된 UI들을 컴포넌트로 추출
  • 상태 관리 및 비즈니스 로직에 집중
  • 화면을 어느 단위로 나누는 것이 효율적일지
  • 가독성 좋은 JSX 작성
  • 디렉토리 구조를 고려

✨ 이번 챌린지의 목표는 하나의 페이지를 데이터와 상태를 기준으로 나누어보는 것입니다.


공용컴포넌트 추출하기

페이지 내에서 2번 이상 사용되는 요소를 컴포넌트로 추출했습니다.

<StartRating />

average 평균값을 받아서 별점으로 표시하는 컴포넌트 입니다.

<Price />

<Price />

<Price size='sm' />

price의 size 기본값은 md 이고 원가와 할인율을 보여줍니다.
사이즈가 md일 때, 원가와 할인율을 꼭 작성하도록 하고싶은데 어떻게 타입을 지정해야할 지 몰라 더 찾아보고 수정하고 싶습니다.

<RocketBage />

type 타입에 따라 배지 이미지를 보여주는 컴포넌트 입니다.
로켓프레쉬나 로켓직구도 이후에 추가할 수 있게 컴포넌트로 분리하면 재사용성이 높을 것 같습니다.


데이터를 기준, 화면 나누기

vendorItemPage에서 사용하는 api는 4개로

  1. 상품정보영역 중 breadcrumb
  2. 상품정보
  3. 다른 상품들
  4. 상품상세

가 있었습니다. 이 데이터를 기준으로 큰 구조를 section으로 나눴습니다.

export default function VendoritemPage() {
  const { item, details, breadcrumble, otherItems } = useProductMock();

  return (
    <Main>
      <Breadcrumble breadcrumble={breadcrumble} />
      <Item item={item} />
      <OtherItems otherItems={otherItems} />
      <Details details={details} />
    </Main>
  );
}

1회차 때 고민했던 api 리팩토링 방식을 사용했으면 좋았겠지만 시간이 부족할 것 같다고 생각해서 일단 데이터만 빨리 받아올 수 있도록 useProductMock이라는 훅으로 데이터를 받아왔습니다. 임시적인 로직이라 mock이라고 이름붙였고 수정을 빨리 하고싶습니다..


Item

왼쪽은 이미지에 대한 정보를 담고 있고 오른쪽은 주문에 필요한 정보를 담고 있어서 ItemImages, ItemInfo 로 구역을 나눴습니다.

const Item = ({ item }: IProps) => {
  if (!item) return <p>item 로딩중...</p>;

  return (
    <section>
      <ItemImages />
      <ItemInfo />
    </section>
  );
};

ItemInfo

여기에선 다루는 데이터도 많고 요소가 많아 생각보다 시간이 들었습니다.
최대한 심플하게 작성하고 싶었고 추상화의 정도를 비슷하게 맞추는 것을 고려하면서 작성했습니다.

const ItemInfo = ({}: IProps) => {
  return (
    <Wrapper>
      <div className='info-header'>
        <BlueLink to='/apple' title='Apple' />
        <Title title='Apple 아이폰 13 mini 자급제' />
        <StarRating />
        <BlueLink to='/review' title='13,130개 상품평' />
      </div>

      <div className='info-price'>
        <Price
          price={902200}
          orignPrice={950000}
          discountRate={5}
          unit={'원'}
        />
        <RocketBage type='ROCKET' />
      </div>

      <div className='info-shipping'>
        <p>무료배송</p>
        <Radio
          title='내일(목) 7/21'
          description='(23시간 57분 내 주문 시 / 서울⋅경기 기준)'
        />
        <Radio
          title='내일(수) 7/27 새벽 7시 전 '
          description='(오후 4시 30분 전 주문 시 / 서울⋅경기 기준)'
        />
      </div>

      <div className='info-insurance'>
        <InsuranceCheck
          title='AppleCare+'
          price={179000}
          description='우발적인 손상에 대한 보상을 받아보세요.'
        />
      </div>

      <div className='info-submit'>
        <CountInput />
        <CartBtn />
        <BuyBtn />
      </div>
    </Wrapper>
  );
};

회고록 작성하려고 기존 참고 사이트 들어가니 그새 품절되어서 다른 상품페이지를 캡쳐했습니다. 배송을 선택할 수 있는 radio input 부분이 없어서 아쉽습니다. 그 부분 데이터가 서버에서 html tag로 데이터를 주는데 어떻게 받아야하는지 몰라 일단 정적으로 만들었습니다.

느낀점

전부 완성하지 못해 아쉬움이 남지만 제출후에 수정을 할 예정입니다.

가독성 좋은 jsx를 작성하기 위해 이번엔 이 영상 | 토스ㅣSLASH 21 - 실무에서 바로 쓰는 Frontend Clean Code에서 추천하는 대로 작성하려고 노력했습니다. 더러울 때 일단 뭉쳐두는 것이 나중에 리팩도링할 때 도움이 된다고 생각해서 기준 없이 일단 뭉쳤었는데, 여기서는 핵심정보는 밖에서 전달받고 몰라도 되는 세부디테일은 숨기는 것이 코드파악에 도움이 된다고 알려주어 이 부분을 많이 고민했습니다.

그리고 이렇게 세부디테일을 숨긴 추상화된 컴포넌트와 아닌 컴포넌트가 섞여있으면 코드를 읽을 때 흐름이 끊길 수 있다는 것도 알게 되어 추상화수준도 비슷하게 맞추려고 했습니다.

썻다 지웠다 한 코드가 많아 진도가 느려서 아쉽긴 했지만 가독성 좋은 jsx를 깊게 고민해볼 수 있어서 좋은 경험이었고
그렇게 고민했는데도 아직 완성도가 떨어지는 걸 보면 배울점이 많다는 것도 느낍니다 😂

3회차 동안 배운 부분을 개인 포트폴리오에 적용해보면서 3주를 보내고 다음 4회차도 더 잘하도록 노력하겠습니다!

0개의 댓글