본문 바로가기

React/실험실

[React] Swiper 잘 쓰기 - AutoPlay Pause Resume

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