본문 바로가기
React/Next.js

[NextJS] Swiper `swiper.params.navigation undefined` 해결하기

by 검은냥냥이 2022. 12. 17.

스와이퍼(Swiper)를 쓰다 보면, Init 과정에서 문제가 생기는 경우 간혹 발생이 됩니다. 인입되는 시점을 변경해 준다면, swiper를 쓰는데 크게 문제는 발생되지 않을 겁니다. 아래의 예제를 통해서 확인하여 수정하면 정상적으로 작동될 겁니다.

원래는 타입스크립트(Typescript)로 사용하지만, 예제는 자바스크립트(Javascript)이니 타입만 추가로 넣어주시면 될 것 같습니다.

 

변경 전

현재 스와이퍼(Swiper) 기준으로 최신 버전이 8.4.5입니다. 참고하여 수정하시면 될 것 같습니다.

import { Swiper, SwiperSlide } from "swiper/react";
import SwiperCore, { Autoplay, Pagination, Navigation } from "swiper";

SwiperCore.use([Autoplay, Pagination, Navigation]);

const Works = () => {
  const navigationPrevRef = React.useRef(null);
  const navigationNextRef = React.useRef(null);
  const [pageLoaded, setPageLoaded] = React.useState(false);
  
  React.useEffect(() => {
    setPageLoaded(true);
  }, [pageLoaded]);
  
  return (
    <section className="work-carousel metro position-re">
      <div className="container-fluid">
        <div className="row">
          <div className="col-lg-12 no-padding">
            <div className="swiper-container">
              <Swiper
                className="swiper-wrapper"
                slidesPerView={2}
                centeredSlides={true}
                loop={true}
                navigation={{
                  prevEl: navigationPrevRef.current,
                  nextEl: navigationNextRef.current,
                }}
                onBeforeInit={(swiper) => {
                  swiper.params.navigation.prevEl = navigationPrevRef.current;
                  swiper.params.navigation.nextEl = navigationNextRef.current;
                }}
                onSwiper={(swiper) => {
                  setTimeout(() => {
                    swiper.params.navigation.prevEl = navigationPrevRef.current;
                    swiper.params.navigation.nextEl = navigationNextRef.current;

                    swiper.navigation.destroy();
                    swiper.navigation.init();
                    swiper.navigation.update();
                  });
                }}
                autoplay={{
                  delay: 2500,
                  disableOnInteraction: false,
                }}
                speed={1000}
                breakpoints={{
                  320: {
                    slidesPerView: 1,
                    spaceBetween: 0,
                  },
                  640: {
                    slidesPerView: 1,
                    spaceBetween: 0,
                  },
                  767: {
                    slidesPerView: 1,
                    spaceBetween: 0,
                  },
                  991: {
                    slidesPerView: 2,
                  },
                }}
              >
                {pageLoaded &&
                  worksData.map((item, index) => (
                    <SwiperSlide className="swiper-slide" key={item.id}>
                      // ...
                    </SwiperSlide>
                  ))}
              </Swiper>

              <div
                ref={navigationNextRef}
                className="swiper-button-next swiper-nav-ctrl simp-next cursor-pointer"
              >
                <span className="simple-btn right">Next</span>
              </div>
              <div
                ref={navigationPrevRef}
                className="swiper-button-prev swiper-nav-ctrl simp-prev cursor-pointer"
              >
                <span className="simple-btn">Prev</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
};

export default Works;

 

변경 후

만약, "onBeforeInit"에서 문제가 생긴다면, "onInit"으로 변경하여 주입되는 시점을 변경해 보면 될 것 같습니다.

import { Swiper, SwiperSlide } from 'swiper/react'
import { Autoplay, Navigation, Pagination } from 'swiper'

const Works = () => {
  const navigationPrevRef = React.useRef(null)
  const navigationNextRef = React.useRef(null)
  const [pageLoaded, setPageLoaded] = React.useState(false)
  
  React.useEffect(() => {
    setPageLoaded(true)
  }, [pageLoaded])
  
  return (
    <section className="work-carousel metro position-re">
      <div className="container-fluid">
        <div className="row">
          <div className="col-lg-12 no-padding">
            <div className="swiper-container">
              <Swiper
                className="swiper-wrapper"
                modules={[Navigation, Autoplay, Pagination]}
                slidesPerView={2}
                centeredSlides={true}
                loop={true}
                lazy={true}
                observer={true}
                observeParents={true}
                navigation={{
                  prevEl: navigationPrevRef.current,
                  nextEl: navigationNextRef.current,
                }}
                onBeforeInit={(swiper) => {
                  swiper.params.navigation.prevEl = navigationPrevRef.current
                  swiper.params.navigation.nextEl = navigationNextRef.current
                  swiper.navigation.init()
                  swiper.navigation.update()
                }}
                autoplay={{
                  delay: 2500,
                  disableOnInteraction: false,
                }}
                speed={1000}
                breakpoints={{
                  320: {
                    slidesPerView: 1,
                    spaceBetween: 0,
                  },
                  640: {
                    slidesPerView: 1,
                    spaceBetween: 0,
                  },
                  767: {
                    slidesPerView: 1,
                    spaceBetween: 0,
                  },
                  991: {
                    slidesPerView: 2,
                  },
                }}
              >
                {pageLoaded &&
                  worksData.map((item, index) => (
                    <SwiperSlide className="swiper-slide" key={item.id}>
                      // ...
                    </SwiperSlide>
                  ))}
              </Swiper>

              <div
                ref={navigationNextRef}
                className="swiper-button-next swiper-nav-ctrl simp-next cursor-pointer"
              >
                <span className="simple-btn right">Next</span>
              </div>
              <div
                ref={navigationPrevRef}
                className="swiper-button-prev swiper-nav-ctrl simp-prev cursor-pointer"
              >
                <span className="simple-btn">Prev</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  )
}

export default Works
728x90
사업자 정보 표시
레플라 | 홍대기 | 경기도 부천시 부일로 519 화신오피스텔 1404호 | 사업자 등록번호 : 726-04-01977 | TEL : 070-8800-6071 | Mail : support@reafla.co.kr | 통신판매신고번호 : 호 | 사이버몰의 이용약관 바로가기