솔로프로젝트 (Coz Shopping 메인 페이지 만들기)

깃 허브 주소 : https://github.com/YunHanKIM/fe-pbl-coz-shopping-phase-1

 

3일간 솔로프로젝트를 시작했다.

프로젝트 초기 설정 시간을 최소화하고 일관된 개발 환경을 제공하기 위해 헤더와 푸터가 이미 완성된 베이스 리포지토리를 제공해주었다.

상품 배열에 해당하는 더미 데이터는 CozShopping API로부터 API 요청을 테스트하여 받은 JSON 응답 데이터를 활용 하였다.

유어클래스에서 알려주는 순서대로 따라서 하나씩 만들어 보았다, 수업때는 이미 코드 구성이 다 되어있고 거기서 빈곳에 코드를 넣는것이였는데 처음부터 만들려고 하니 어디서 시작해야 할지 막막했다.

처음에 생각했을때 과제중에 트위터처럼 라우터 돔을 사용하여 탭에 있는 각각 항목마다 링크를 달아서 하려고 했다. 이렇게 하니까 각 항목마다 컴포넌트를 만들고 해야해서 더 복잡해지고 어렵게 느껴졌다. 그래서 강사님께 "{Link}를 사용해서 이런식으로 하려고 하는데 너무 복잡하게 하는건가요?" 라고 질문을 했다. 강사님께서 굳이 새로고침해서 불러오는 환경이 아니라서 링크를 사용할 필요가 없다고 하여서 다시 처음부터 시작하였다. 그래서 시간이 많이 걸린거 같다. 하다가 도저히 안될거 같아 강사님이 오전, 오후에 같이 수업을 하며 알려주신 코드를 가지고 보면서 만들었다. 그리고 거의 시간을 css 만지는데 사용한거 같다. 이 솔로 프로젝트를 통해서 배운건 많지만 혼자 처음부터 하려고 하니 어디서 부터 손을 데야할지 감도 안오고 어렵게만 느껴졌다. 그래도 팀 프로젝트 전에 이런 과정을 겪어서 내 실력이 많이 부족하다는걸 더 느끼게 되었다. 본격적으로 팀 프로젝트에 들어가서 팀에게 피해를 주지않기위해 더 공부를 하고 손으로 직접 느끼면서 해보아야겠다.

이것을 통해서 일단 작은것 부터 하나씩 만들어 가면서 점점 크게 만드는 형태로 설계를 해야하겠구나 생각했다. 어떻게 화면을 구성해야하고 어떤 방식으로 해야할지 많이 느낀 3일이였다. 그리고 최종적으로 만든 메인페이지를 보며 뿌듯했다, 시간을 이렇게 써서 결국 만들기는 만들었구나 하며 여기서 더 추가 해볼것은 반응형 웹 사이트로 만드는 것이다.

 

최종적으로 이런 메인 페이지 만드는것이 목표

Mission 1. 카테고리 박스 UI 만들기


사용자가 다양한 상품을 카테고리별로 쉽게 탐색할 수 있는 카테고리 박스 UI를 만듭니다.

Subject 1. 상품을 담을 아이템 컴포넌트 만들기


좌: 예시, 우: 만든 ItemCard

우선 상품 이미지와 상품 제목, 상품 가격으로 구성된 ItemCard 컴포넌트를 하나 만든다.

ItemCard.jsx 파일을 생성하여 작성했다.

  1. 아이템 컴포넌트를 생성합니다.
export default function ItemCard({ item, showDetail }) {
  return (
    <div className="item_card">
      <img src={item.imageUrl} height="240px" />
      <div className="item_card_title">{item.title}</div>
      {/* showDetail prop이 true일 때 상세 정보를 표시 */}
      {showDetail && (
        <div>
          {/* 할인 정보가 있을 경우 */}
          {item.discountPercentage ? (
            // 할인 정보를 표시하는 div 태그, 스타일은 flex 및 간격 설정
            <div style={{ display: 'flex', gap: '10px' }}>
              {/* 할인 전 가격에 취소선 적용 */}
              <span style={{ textDecoration: 'line-through' }}>
                {item.price}원
              </span>
              {/* 할인율을 강조하는 빨간색 텍스트 표시 */}
              <span style={{ color: 'orange' }}>
                {item.discountPercentage}% 할인
              </span>
              {/* 할인 후 가격 표시 */}
              <div className="item_discountPrice_after">
                <span>{item.discountPrice}원</span>
              </div>
            </div>
          ) : (
            // 할인 정보가 없을 경우 일반 가격 표시
            `${item.price}원`
          )}
        </div>
      )}
    </div>
  );
}

Subject 2. 상품 목록을 담을 컨테이너 컴포넌트 만들기

 

좌: 예시, 우: 만든 CategoryBox

상품 컴포넌트 배열을 담을 컨테이너 컴포넌트이다.

CategoryBox.jsx 파일을 생성하여 만들었다.

  1. 컨테이너 컴포넌트를 생성합니다. 이 컴포넌트는 아이템 컴포넌트들을 그리드 형식으로 정렬하여 보여주는 역할을 합니다.
  2. 상품 배열에 해당하는 더미 데이터는 CozShopping API로부터 API 요청을 테스트하여 받은 JSON 응답 데이터를 활용합니다.
    1. 먼저 몇 개의 아이템을 표시할 지 고민하고 이를 limit 쿼리 파라미터에 전달합니다. (기본값은 10입니다.)
  3. map 함수를 사용하여 상품 데이터 배열을 상품 컴포넌트 배열로 변환합니다.
import ItemCard from '../components/ItemCard';

// CategoryBox 함수형 컴포넌트 정의, items prop을 받음
export default function CategoryBox({ items }) {
  // console.log({ items });
  return (
    // 상품 카드들을 감싸는 div 태그, 클래스 이름은 "items_container"
    <div className="items_container">
      {/* items 배열을 순회하며 각 상품에 대해 ItemCard 컴포넌트를 렌더링 */}
      {items.map((item) => (
        <ItemCard item={item} showDetail={true} />
      ))}
    </div>
  );
}

Subject 3. 카테고리 목록을 담을 탭 메뉴 컴포넌트 만들기,

Subject 4. API에서 받은 데이터를 컴포넌트에 전달하기


좌: 예시, 우: 만든 탭 메뉴 컴포넌트

  • 다양한 카테고리를 나열할 수 있는 탭 메뉴 컴포넌트(e.g., CategoryTab)를 만듭니다.
  • 탭 메뉴와 상품 목록을 포함하는 컨테이너 컴포넌트를 만듭니다.
  1. 탭 메뉴 컴포넌트를 생성합니다. 사용자가 다양한 상품 카테고리를 쉽게 탐색하고 전환할 수 있게 해주는 인터페이스를 제공합니다.
  2. 각 탭은 카테고리의 이름을 표시하며, 선택된 탭은 시각적으로 구분될 수 있어야 합니다.
    1. 카테고리 배열에 해당하는 더미 데이터는 Swagger API 문서에서 API 요청을 테스트하여 받은 JSON 응답 데이터를 활용합니다.
  3. 컴포넌트의 재사용성을 위해, 카테고리 데이터를 외부로부터 props를 통해 전달받을 수 있도록 설계합니다.
  • 더미 데이터가 아닌 API 호출을 통해 받은 데이터를 컴포넌트에 전달하고 화면에 렌더링합니다.
  1. fetch 함수 또는 axios 라이브러리를 사용하여 CozShopping API로부터 카테고리 데이터를 요청합니다.
  2. API로부터 받은 데이터를 상태에 저장하기 위해 useState 훅을 활용합니다.
  3. 컴포넌트가 마운트될 때 API 호출이 실행되도록 useEffect 훅을 사용합니다.
  4. 데이터가 성공적으로 로드되면, 이를 탭 메뉴 및 상품 목록 컴포넌트로 전달하여 UI를 동적으로 업데이트합니다.
import logo from '../assets/coz_logo_192.png';

// TabItem 함수형 컴포넌트 정의
const TabItem = ({ onClick, title, imageUrl, isActive }) => {
  return (
    // 카테고리 탭을 감싸는 div 태그, 클래스 이름은 "tab_item"
    <div className="tab_item">
      <img src={imageUrl} alt={title} height={'50px'} />

      {/* 탭의 텍스트를 나타내는 span 태그, 클릭 이벤트를 처리하는 onClick prop을 받음 */}
      <span
        onClick={onClick}
        style={{ color: `${isActive ? 'blue' : 'black'}` }}
      >
        {title}
      </span>
    </div>
  );
};

// CategoryTab 함수형 컴포넌트 정의
export default function CategoryTab({ categories, setSelectedId, selectedId }) {
  return (
    // 카테고리 탭을 감싸는 div 태그, 클래스 이름은 "category_tab"
    <div className="category_tab">
      {/* "전체" 카테고리 탭, setSelectedId 함수로 클릭 시 selectedId를 null로 설정 */}
      <TabItem
        title="전체"
        imageUrl={logo}
        onClick={() => setSelectedId(null)}
        // 현재 선택된 카테고리인지 여부를 나타내는 isActive prop 설정
        isActive={selectedId === null}
      />

      {/* 카테고리 데이터를 순회하며 각각의 카테고리에 대한 TabItem을 렌더링 */}
      {categories?.product?.map(({ imageUrl, title, id }) => (
        <TabItem
          imageUrl={imageUrl}
          title={title}
          // setSelectedId 함수로 클릭 시 선택된 카테고리의 id를 설정
          onClick={() => setSelectedId(id)}
          // 현재 선택된 카테고리인지 여부를 나타내는 isActive prop 설정
          isActive={selectedId === id}
        />
      ))}
    </div>
  );
}

Subject 5. 특정 카테고리 선택 시 해당 카테고리의 상품 목록 가져오기


좌: 예시, 우: 만든 화면

탭 메뉴에서 특정 카테고리를 선택하면, 해당 카테고리에 속하는 상품들만을 렌더링하는 기능을 구현

  1. 탭 메뉴 컴포넌트에 각 카테고리를 선택하는 이벤트 핸들러를 구현합니다.
  2. 선택된 카테고리에 따라 상품 목록을 필터링하여 표시하는 로직을 컴포넌트 내에 추가합니다.
  3. 상태 관리를 통해 사용자가 선택한 카테고리를 추적하고, 해당 상태에 따라 필터링된 상품 목록을 관리합니다.
  4. 선택된 카테고리의 상품 목록을 가져오기 위해 API 요청을 보낼 때, 선택된 카테고리에 해당하는 파라미터를 요청에 포함시킵니다.

탭 메뉴에 마우스를 올리면 저렇게 파란색 배경으로 바뀐다. 일정 시간이 지날경우 탭 메뉴의 글자색이 파란색으로 바뀌면서 메뉴항목이 바뀌면서 카테고리 상품이 바뀌는걸 볼 수 있다.

Mission 2. 랭킹별/추천별 상품 슬라이더 UI 만들기


Subject 1. 상품 슬라이더 컴포넌트 만들기


ItemSilider.jsx 파일을 생성한다.

랭킹별 및 추천별 상품을 표시하는 슬라이더 UI 그룹을 만듭니다.

  1. 슬라이더 컴포넌트를 메인 컴포넌트 영역 아래에 생성합니다. 이 컴포넌트는 10개의 상품 데이터를 담은 배열을 입력(props)으로 받아 슬라이더 형태로 표시합니다.
  2. 슬라이더 내에 표시될 상품 아이템 컴포넌트는 이전에 만든 아이템 컴포넌트(e.g., ItemCard)를 재사용합니다.
  3. 슬라이더는 10개의 상품을 한번에 보여주지 않습니다. 대신, 사용자가 좌우 버튼을 통해 상품 목록을 스와이프할 수 있도록 구현합니다.
  4. 더미 데이터를 사용하여 슬라이더의 기능과 레이아웃을 테스트합니다. 이를 통해 실제 API 연결 전에 컴포넌트의 동작을 확인할 수 있습니다.

일정 시간이 지남에 따라 슬라이더 화면이 자동으로 넘어가게 만들었다.

react-slick을 설치하여 간편하게 슬라이더를 구현했다.

// React에서 슬라이더를 구현하는 컴포넌트

// react-slick 라이브러리에서 Slider 컴포넌트를 가져옴
import Slider from 'react-slick';
import ItemCard from './ItemCard';

// ItemSlider 함수형 컴포넌트 정의, title과 list prop을 받음
export default function ItemSlider({ title, list }) {
  // Slider 컴포넌트에 적용될 설정 객체
  const settings = {
    dots: false, // 페이지 점 표시 여부
    infinite: true, // 무한 반복 여부
    speed: 500, // 전환 속도
    slidesToShow: 5, // 보여질 슬라이드 수
    slidesToScroll: 5, // 스크롤 시 이동할 슬라이드 수
    arrows: true, // 화살표 표시 여부
    accessibility: true, // 접근성 활성화 여부
    autoplay: true, // 자동 재생 여부
  };
  return (
    <section className="slider">
      {/* 제목을 나타내는 h1 태그, 스타일은 글자 크기와 색상 설정 */}
      <h1 style={{ fontSize: '24px', color: 'blue' }}>{title}</h1>
      {/* react-slick의 Slider 컴포넌트, 설정은 settings 객체로 전달 */}
      <Slider {...settings}>
        {/* 각각의 아이템에 대해 ItemCard 컴포넌트를 렌더링 */}
        {list.map((item) => (
          <ItemCard item={item} />
        ))}
      </Slider>
    </section>
  );
}

Subject 2. 랭킹별 상품 슬라이더 만들기, Subject 3. 추천별 상품 슬라이더 만들기


위에서 구성한 슬라이더 컴포넌트에 컴포넌트는 CozShopping API에서 제공하는 추천별 상품 데이터를 활용하여 랭킹별, 추천별 상품 슬라이더를 만들었다.

+ Recent posts