Shadcn UI와 TailwindCSS로 동적 캐러셀 컴포넌트 구현하기
2025-01-21 12:16:25Shadcn UI, TailwindCSS, ViteJS와 ReactJS로 동적 캐러셀 컴포넌트 구성
웹 개발에서 사용자 경험을 향상시키고 다양한 콘텐츠를 매력적으로 제공하기 위해 캐러셀은 중요한 UI 요소입니다. 이번 글에서는 Shadcn UI, ViteJS, TailwindCSS, 그리고 ReactJS와 TypeScript를 활용하여 동적 캐러셀 컴포넌트를 만드는 방법을 자세히 살펴보겠습니다. 완성된 컴포넌트는 다양한 프로젝트에 재사용 가능하며, 성능과 사용자 경험을 두루 갖춘 매력적인 UI를 제공합니다.
프로젝트 초기 설정
시작하기 전에 Node.js와 npm 혹은 Yarn이 시스템에 설치되어 있는지 확인하세요.
1. 프로젝트 초기화
Vite의 최신 버전을 이용해 React와 TypeScript를 포함한 프로젝트를 초기화합니다.
npm create vite@latest
cd my-carousel
npm install
2. 필요한 패키지 설치
캐러셀 구현을 위해 다음 패키지들을 추가로 설치합니다.
npm install embla-carousel-react embla-carousel-autoplay
npm install -D tailwindcss postcss autoprefixer
npx shadcn@latest init
TailwindCSS 설치 및 설정
TailwindCSS는 빠르고 유연한 스타일링을 제공하며, 숙련된 개발자라면 화면의 반응성을 효율적으로 관리할 수 있습니다. TailwindCSS의 공식 문서를 참고하여 설치 및 설정을 완료하세요.
Shadcn UI 설치 및 설정
Shadcn UI는 사전 제작된 컴포넌트와 유틸리티를 제공하여 개발 속도를 높입니다. 이번 예제에서는 Carousel과 Button 컴포넌트를 사용할 예정입니다. Shadcn UI의 공식 문서를 참조하여 프로젝트에 설정하세요.
커스텀 캐러셀 컴포넌트 작성
src/custom-carousel.tsx 파일에 다음과 같은 CustomCarousel 컴포넌트를 추가합니다:
import {
Carousel,
CarouselApi,
CarouselContent,
CarouselItem,
} from "@/components/ui/carousel";
import Autoplay from "embla-carousel-autoplay";
import { useCallback, useEffect, useState } from "react";
import { Button } from "./components/ui/button";
export const CustomCarousel = () => {
const [carouselAPI, setCarouselAPI] = useState<CarouselApi | null>(null);
const [selectedIndex, setSelectedIndex] = useState(0);
const [scrollSnaps, setScrollSnaps] = useState<number[]>([]);
const onSelect = useCallback(() => {
if (!carouselAPI) return;
setSelectedIndex(carouselAPI.selectedScrollSnap());
}, [carouselAPI]);
const scrollTo = (index: number) => {
if (!carouselAPI) return;
carouselAPI.scrollTo(index);
};
useEffect(() => {
if (!carouselAPI) return;
onSelect();
setScrollSnaps(carouselAPI.scrollSnapList());
carouselAPI.on("select", onSelect);
}, [carouselAPI, onSelect]);
return (
<div>
<Carousel
plugins={[Autoplay({ delay: 2500 })]}
opts={{ loop: true, align: "center" }}
setApi={setCarouselAPI}
>
<CarouselContent>
{[...Array(6)].map((_, index) => (
<CarouselItem key={index} className="md:basis-1/2">
<div className="border rounded-md h-[16rem] bg-muted/50 flex items-center justify-center md:h-[20rem]">
<p className="font-bold text-2xl text-muted-foreground">
{index + 1}
</p>
</div>
</CarouselItem>
))}
</CarouselContent>
</Carousel>
<div className="flex justify-center mt-4 space-x-2">
{scrollSnaps.map((_, index) => (
<Button
key={index}
onClick={() => scrollTo(index)}
size="icon"
className={`w-2 h-2 rounded-full ${
selectedIndex === index ? "bg-primary" : "bg-gray-300"
}`}
/>
))}
</div>
</div>
);
};
코드 설명
상태 관리
carouselAPI: 캐러셀 API 객체를 저장하여scrollTo와selectedScrollSnap같은 메서드에 접근할 수 있게 합니다.selectedIndex: 현재 선택된 슬라이드의 인덱스를 추적합니다.scrollSnaps: 슬라이드의 인덱스를 나타내는 스냅 포인트 배열을 저장합니다.
이벤트 처리
onSelect: 사용자가 새 슬라이드를 선택할 때마다selectedIndex를 업데이트하여 UI를 캐러셀 상태와 동기화합니다.scrollTo: 특정 슬라이드로 프로그램적으로 이동할 수 있게 하여 버튼이나 기타 제어 요소를 통한 상호작용을 가능하게 합니다.
생명주기 관리
useEffect 훅은 캐러셀 초기화가 올바르게 이루어지도록 보장합니다:
- 초기 상태를 동기화하기 위해
onSelect를 호출합니다. carouselAPI.scrollSnapList를 사용해scrollSnaps를 설정합니다.selectedIndex업데이트를 위해 이벤트 리스너를 추가합니다.
결론
축하합니다! 이제 Shadcn UI, ViteJS, TailwindCSS, 그리고 ReactJS 및 TypeScript를 활용하여 동적이고 재사용 가능한 캐러셀 컴포넌트를 완성했습니다. 스타일을 커스터마이징하거나 새로운 기능을 추가하는 등 다양한 방식으로 확장할 수 있습니다. 댓글로 여러분의 경험을 공유해주세요!