React에서 슬라이드를 구현하는 방법 중 하나가 Swiper 라이브러리를 사용하는 것이다.
간단한 기능은 구현하는데 어려움이 없으나 개발하다보면 특이한 기능이 필요한 경우가 있다.
그런 기능을 직접 구현해보면서 아카이빙할 계획이다.
일반적인 Auto Play 컴포넌트이다.
<Swiper
loop={true}
autoplay={{
delay: 10000,
disableOnInteraction: false,
}}
modules={[Autoplay]}
>
// ...
</Swpier>
몇가지 옵션을 필요에 따라 줄 수 있겠지만 Auto Play를 위한 옵션만 주었다.
( 옵션 설명 생략 ! )
Pause Resume
먼저 자동 재생 기능을 사용하면 Progress가 나오는 경우가 있다.
다음 스크롤로 언제쯤 이동되는지 알려주는 기능이다. 해당 기능은 이미 Swiper의 데모에 잘 나와있는데,
const handleAutoplayTimeLeft = (s, time, progress) => {
progressCircle.current.style.setProperty("--progress", 1 - progress);
progressContent.current.textContent = `${Math.ceil(time / 1000)}s`;
};
// ...
<Swiper
loop={true}
autoplay={{
delay: 10000,
disableOnInteraction: false,
}}
modules={[Autoplay]}
onAutoplayTimeLeft={handleAutoplayTimeLeft} << ---
>
// ...
<PauseResumeProgress className="autoplay-progress" slot="container-end">
<svg viewBox="0 0 48 48" ref={progressCircle}>
<circle cx="24" cy="24" r="20"></circle>
</svg>
<span ref={progressContent}></span>
</PauseResumeProgress>
</Swiper>
onAutoplayTimeLeft를 통해서 다음 스크롤이 넘어가기까지의 시간을 알 수 있다.
이때 state가 아닌 ref를 통해서 값을 관리하는 이유는 상태가 업데이트되면 해당 컴포넌트가 리렌더링이 발생하고
이것으로 컴포넌트가 정상적으로 작동하지 않을 수 있다.
그래서 ref를 통해서 값을 관리하면서 리렌더링은 피하는 것이다.
여기까지는 Demo를 보면 충분히 알 수 있는 부분이다.
하지만 여기서 하나의 기능이 추가되면?
바로 클릭을 통해서 스크롤이 멈추는 기능이다.
사실 이 기능 역시 API 명세에는 다 있는 기능이다. 하지만 내가 실수한 부분이 있다.
명세를 보면 pause와 resume / start와 stop이 하나의 세트로 구성되어 있다.
이때 앞서 구현한 Progress 기능을 유지하면서 일시 정지 / 재생 기능을 구현하려면 pause와 resume을 사용해야 한다.
start와 stop을 사용하면 Auto Play가 멈추고 다시 실행되는 것은 동일하지만 Progress는 멈춘 시간에 대한 값을
가지고 있다.
이게 무슨뜻이냐면 5초 뒤 다음 슬라이드로 이동하는 슬라이드에서 2초 재생하다가 stop을 사용하고
10초 뒤 start를 하게 되면 progress와 time은 12초의 값을 가지게 된다.
우측 아래에 progress가 고장나는게 보일 것이다. ( 아주 작게 ... )
const handleToggleSlider = () => {
const autoplay = sliderRef.current.autoplay;
if (autoplay.running) {
autoplay.stop();
} else {
autoplay.start();
}
};
<Swiper
loop={true}
autoplay={{
delay: 3000,
disableOnInteraction: false,
}}
onSwiper={(swiper) => {
sliderRef.current = swiper;
}}
modules={[Autoplay]}
onAutoplayTimeLeft={handleAutoplayTimeLeft}
>
// ...
</Swiper>
onSwiper를 통해서 Swiper의 제어를 얻어서 stop을 사용하면 앞서 말한 것처럼 슬라이드 자체는 멈추지만
progress의 시간은 흐르기 때문에 우리가 원하는 기능을 구현할 수 없다.
여기서 pause와 resume을 사용하면 우리가 원하는 기능을 구현할 수 있다.
const handleToggleSlider = () => {
const autoplay = sliderRef.current.autoplay;
if (autoplay.paused) {
autoplay.resume();
} else {
autoplay.pause();
}
};
크게 어려운 기능은 아니지만 본인은 이 기능때문에 1시간을 삽질했고 다른 누군가가 삽질을 하다가 나의 글을 발견해서
도움을 받았으면 좋겠다!
'React > 실험실' 카테고리의 다른 글
[React] Children (0) | 2023.12.10 |
---|---|
[React] Effect가 필요하지 않을 수 있다. (1) | 2023.11.20 |
[React] 빌어먹을 iOS - vh 편 (0) | 2023.08.29 |
[React] 메일 템플릿 만들기 (1) | 2023.08.07 |
[React] day.js vs moment.js (0) | 2023.06.22 |