Embla Carousel 라이브러리를 사용하여 다음과 같은 슬라이더를 만드는법을 공유해보려고한다.
Embla-Carousel -> https://www.embla-carousel.com/
npm install embla-carousel-react --save
위 명령어로 패키지를 설치한다.
패키지를 설치했으면 파일을 하나 만들고 다운받은 패키지를 import 한다.
import React, { ReactNode, useCallback, useEffect, useState } from "react";
import useEmblaCarousel, { EmblaOptionsType } from "embla-carousel-react";
useEmblaCarousel
은 Embla 캐러셀을 구현하기 위한 핵심 패키지라고 이해하면 되고,
EmblaOptionsType
패키지는 타입스크립트 사용자들을 위한 Embla 캐러셀 슬라이더의 옵션들이 정의된 타입이다.
전체 코드를 보면서 설명하도록 하겠다.
위 GIF를 구현한 코드는 다음과 같다.
import React, { ReactNode, useCallback, useEffect, useState } from "react";
import useEmblaCarousel, { EmblaOptionsType } from "embla-carousel-react";
type PropType = {
options?: EmblaOptionsType;
slides: ReactNode[];
};
export const EmblaCarousel = (props: PropType) => {
const { options, slides } = props; // props로 가져온 옵션과 슬라이드 리스트
const [emblaRef, embla] = useEmblaCarousel(options); // 슬라이더 구현에 필요한 요소들을 useEmblaCarousel 에서 가져온다.
const [selectedIndex, setSelectedindex] = useState(0); // 현재 보여지는 인덱스를 설정
const [scrollSnaps, setScrollSnaps] = useState<number[]>([]); // 스크롤 스냅 Point 를 설정할 때 사용할 state
// 이 코드는 구현할 때 사용하지 않았다. 하지만 나중에 혹시 쓰일 수 있을 것 같아서 남겨뒀다.
const scrollTo = useCallback(
(index: number) => embla && embla.scrollTo(index),
[embla]
);
// 현재 선택된 슬라이더의 순서(인덱스)를 저장을 위한 함수
const onSelect = useCallback(() => {
if (!embla) return;
setSelectedindex(embla.selectedScrollSnap());
// selectedScrollSnap: 선택한 스냅 Point의 인덱스를 가져온다.
}, [embla, setSelectedindex]);
useEffect(() => {
if (!embla) return;
onSelect();
setScrollSnaps(embla.scrollSnapList());
embla.on("select", onSelect);
}, [embla, setScrollSnaps, onSelect]);
return (
<div className="w-full relative rounded-md ">
<div className="overflow-hidden relative rounded-md" ref={emblaRef}>
<div className="flex flex-col flex-wrap h-44 flex-none">
{slides.map((slide, index) => (
<div className="w-full h-44 relative mx-1" key={index}>
{slide}
</div>
))}
</div>
<div className="absolute right-2 bottom-2 bg-[#0e0e0e72] rounded-full">
<div className="flex justify-evenly items-center text-xs w-9 font-semibold">
<span className="text-white">{selectedIndex + 1}</span>
<div className="w-[2.05px] h-[2.05px] rounded-full bg-[#ffffffb2]" />
<span className="text-[#ffffffb2]">{slides.length}</span>
</div>
</div>
</div>
</div>
);
};
export default EmblaCarousel;
아래는 EmblaCarousel을 호출한 부분의 코드이다.
<div className="flex justify-center items-center w-full h-44 rounded-md font-thin text-xl my-3">
<Carousel
slides={[
<Image
key={0}
layout="fill"
src={`/images/대책위원회1.jpg`}
className=" object-cover rounded-md"
alt="Image"
></Image>,
<Image
key={1}
src={`/images/대책위원회2.jpg`}
layout="fill"
className=" object-cover rounded-md"
alt="Image"
></Image>,
<Image
key={2}
src={`/images/대책위원회3.jpg`}
layout="fill"
className=" object-cover rounded-md"
alt="Image"
></Image>,
]}
options={{
align: "start",
loop: true,
skipSnaps: false,
inViewThreshold: 0.7,
}}
/>
</div>
props로 slides와 options가 들어가는데, slides에는 배열안에 이미지 코드들을 넣어주었고, options prop에는 Embla Slider에 적용할 옵션들을 명시해주었다.
설명이 많이 부족한데, ( 특히 ScrollSnap 관련된 설명 )
한번 직접 콘솔에 찍어보면 Snap Point가 어떤 느낌인지 바로 알 수 있을 것이다!