Custom Stop and Play Buttons for Swiper.js Autoplay (React/Next)

Viewed 137

I have been trying to create a Swiper that utilizes Swiper.js' autoplay functionality to stop and play, in React. I followed their instructions as best I could and did lots of research trying to find an answer. I was even able to confirm my setup (somewhat) through a jQuery example that does the same thing, but even that reference didn't help in React.

Here's what I've got so far:

// Note: I am using Next.js,
// so there are some minor differences from React,
// but they shouldn't affect the Swiper.
import { useRef } from 'react'
import { Swiper, SwiperSlide } from 'swiper/react'
import { Autoplay, Pagination, EffectCreative } from 'swiper'
import 'swiper/css'
import 'swiper/css/pagination'

const App = () => {

  const heroSwiper = useRef(null)

  // Both functions below return an error:
  // TypeError: undefined is not an object
  // (evaluating 'heroSwiper.current.autoplay.start')
  const playHero = () => {
    heroSwiper.current.autoplay.start()
  }
  const pauseHero = () => {
    heroSwiper.current.autoplay.stop()
  }

  return (
    <>

      // ... Other content

      <Swiper
        ref={heroSwiper}
        direction='horizontal'
        speed={2500}
        loop={true}
        grabCursor={true}
        autoplay={{
          disableOnInteraction: false,
          delay: 3500
        }}
        effect={'creative'}
        creativeEffect={{
          prev: {
            translate: ['-50%', 0, -100],
          },
          next: {
            translate: ['100%', 0, 0],
          }
        }}
        pagination={{
          clickable: true,
        }}
        modules={[ Autoplay, EffectCreative, Pagination ]}
      >

        <SwiperSlide>
          <span>1</span>
        </SwiperSlide>
        <SwiperSlide>
          <span>2</span>
        </SwiperSlide>
        <SwiperSlide>
          <span>3</span>
        </SwiperSlide>
        <SwiperSlide>
          <span>4</span>
        </SwiperSlide>
        <SwiperSlide>
          <span>5</span>
        </SwiperSlide>
        <SwiperSlide>
          <span>6</span>
        </SwiperSlide>

        <div>
          <button type='button' onPointerUp={playHero}>Play</button>
          <button type='button' onPointerUp={pauseHero}>Pause</button>
        </div>

      </Swiper>

      // ... Other content

    </>
  )
}

export default App

Thanks for the responses!

2 Answers

There is a mistake to use ref for swiper component.

Use a state variable instead of const heroSwiper = useRef(null);

const [heroSwiper, setSwiperRef] = useState(null);

And then set setSwiperRef in onSwiper prop.

<Swiper
  // ref={heroSwiper} // This is wrong
  onSwiper={setSwiperRef}

Finally, use the state variable to change start/stop of slider.

  const playHero = () => {
    heroSwiper.autoplay.start();
  };
  const pauseHero = () => {
    heroSwiper.autoplay.stop();
  };

Please let me know if it works!

I figured it out! In Swiper.js' JavaScript example, they use a constant to reference the Swiper function—not the element.

const swiper = new Swiper('.swiper', {
 autoplay: {
   delay: 5000,
 },
})

This was confusing to me, since in React, Swiper.js handles the initialization.

Thankfully, I found—in a different section—they said "After you initialize Swiper it is possible to access to Swiper's instance on its HTMLElement. It is swiper property of Swiper's HTML container element:"

const swiper = document.querySelector('.swiper').swiper

Seeing how they reference swiper inside the element made me realize that I just needed to reference swiper inside my reference.

const playHero = e => {
  e.preventDefault()
  heroSwiper.current.swiper.autoplay.start()
}
const pauseHero = e => {
  e.preventDefault()
  heroSwiper.current.swiper.autoplay.stop()
}

It makes sense, but their documentation doesn't make this clear, since it's written in vanilla JavaScript only.

I hope this helps anyone else having this issue.

Related