[코드잇 스프린트] 고급 프로젝트 (인기 체험)

이언덕·2025년 6월 21일
post-thumbnail

🔥 인기 체험 영역과 ArrowButton 기능 분석

📌 인기 체험 영역: API 연결부터 렌더링까지

🧩 관련 상태 (useState)

const [popularActivities, setPopularActivities] = useState<ActivityType[]>([]);
const [slideIndex, setSlideIndex] = useState(0);
const [itemsPerSlide, setItemsPerSlide] = useState(4);
  • popularActivities: 인기 체험 데이터를 담는 상태.
  • slideIndex: 현재 페이지(슬라이드)의 인덱스.
  • itemsPerSlide: 슬라이드당 보여줄 카드 수.



🔗 API 연결 (인기 체험 리스트 조회)

useEffect(() => {
  const fetchPopularActivities = async () => {
    try {
      const response = await activityService.getActivities({
        query: {
          method: "offset",
          sort: "most_reviewed",
        },
      });
      setPopularActivities(response.data.activities);
    } catch (error) {
      console.error("Error fetching popular activities:", error);
    }
  };
  fetchPopularActivities();
}, []);
  • sort: "most_reviewed"를 통해 리뷰 수가 많은 순서로 인기 체험 데이터를 받아옴.
  • 받아온 데이터를 setPopularActivities에 저장.



🖼 렌더링 방식

슬라이드 방식으로 인기 체험을 보여주기 위해 데스크탑/태블릿 그리드모바일용 슬라이드를 구분하여 렌더링한다.

✅ 데스크탑/태블릿용 그리드 (페이지네이션 방식)

const paginatedActivities = popularActivities?.slice(
  slideIndex * itemsPerSlide,
  slideIndex * itemsPerSlide + itemsPerSlide,
);
  • slice()로 현재 슬라이드 인덱스에 따라 일부 항목만 잘라서 보여줌.
<div className="grid tablet:grid-cols-2 desktop:grid-cols-4 ...">
  {paginatedActivities?.map((activity) => (
    <Card
      key={activity.id}
      title={activity.title}
      price={activity.price}
      bannerImageUrl={activity.bannerImageUrl}
      rating={activity.rating}
      reviewCount={activity.reviewCount}
    />
  ))}
</div>

.

📱 모바일용 가로 스크롤 슬라이드

<div className="flex overflow-x-auto snap-x snap-mandatory ...">
  {popularActivities.map((activity) => (
    <div key={activity.id} className="flex-shrink-0 w-[85%] snap-start">
      <Card ... />
    </div>
  ))}
</div>
  • 모바일에서는 슬라이드를 직접 넘길 수 있도록 scrollable 가로 레이아웃으로 구성되어 있음.



결과물 🖥️



🎯 ArrowButton 작동 방식

⬅ 버튼 클릭 시 실행되는 로직

ArrowButton 컴포넌트의 onClick에는 아래와 같은 함수가 연결되어 있다

<ArrowButton
  onClick={() =>
    setSlideIndex(
      (prev) =>
        (prev + 1) % Math.ceil(popularActivities.length / itemsPerSlide),
    )
  }
/>

.

작동 방식 해석:

  1. 현재 슬라이드 인덱스를 +1 증가시킴.
  2. 전체 페이지 수(popularActivities.length / itemsPerSlide)를 초과하지 않도록 % 연산자 사용해 순환.
  3. 다시 slideIndex가 변경되면, 위에서 정의한 paginatedActivities가 다시 계산되어 렌더링됨.



👇 예시:

  • popularActivities.length = 8, itemsPerSlide = 4 → 총 2페이지.
  • 현재 slideIndex = 0이면, 버튼 클릭 시 slideIndex = 1.
  • 다시 클릭하면 (1 + 1) % 2 = 0으로 돌아가며 무한 순환.

🖥️ 결과물



✅ 전체 흐름 요약

  • getActivities(sort: "most_reviewed")로 인기 체험을 가져온다.
  • 데스크탑에서는 slice 기반 슬라이드, 모바일에서는 가로 스크롤 슬라이드.
  • ArrowButton 클릭 시 슬라이드 인덱스를 순환하며 다음 페이지를 보여준다.
  • 전체 구조는 상태 기반 페이징 + 반응형 디자인으로 구성되어 유연하고 직관적이다.

0개의 댓글