Next.js React Swiper 사용법 및 Image 컴포넌트 최적화 Next.js에서 React Swiper 라이브러리를 사용하는 방법과 이미지 컴포넌트를 사용하여 이미지 최적화하는 방법을 알아보겠습니다.
Next.js를 사용하면서 슬라이드를 구현할 때 여러가지 라이브러리가 있지만 그 중에서 Swiper(React Swiper) 라이브러리를 사용하여 구현하는 방법과 이미지 컴포넌트 사용과 슬라이드시 이미지가 늦게 뜨는 현상을 해결하고 이미지 size 경고 처리 방법 등 다양한 내용을 알아보겠습니다.
먼저 React Swiper 라이브러리를 설치합니다.
`Swiper 공식홈페이지 `
npm install swiper
swiper를 설치하셨다면 이제 swiper css를 위치에 맞게 import 해줍니다.
swiper를 여러 페이지에서 사용할 것이라면 최상단 레이아웃에 import 해주시면 됩니다.
swiper css import 할때 각 컴포넌트 및 페이지에서 모두 import 할 경우 중복으로 인해 css가 꼬일 수 있으니 app/layout.tsx
에 import 해주시는 것을 추천합니다.
app/layout.tsx import 'swiper/css' ;
import 'swiper/css/navigation' ;
import 'swiper/css/pagination' ;
Swiper 컴포넌트를 구현합니다.
import { Swiper , SwiperSlide } from 'swiper/react' ;
import SwiperCore , { Navigation , Pagination } from 'swiper' ;
const SwiperComponent = () => {
return (
< Swiper >
< SwiperSlide > Slide 1 </ SwiperSlide >
< SwiperSlide > Slide 2 </ SwiperSlide >
< SwiperSlide > Slide 3 </ SwiperSlide >
</ Swiper >
);
};
export default SwiperComponent ;
자주 사용하는 옵션 목록
옵션명 설명 spaceBetween
슬라이드 사이의 간격 slidesPerView
한번에 보여줄 슬라이드 수 navigation
이전/다음 버튼 pagination
페이지 버튼 autoplay
자동 슬라이드 loop
무한 슬라이드
components/SwiperComponent.tsx // ... 생략
const SwiperComponent = () => {
return (
< Swiper
spaceBetween = { 20 }
slidesPerView = { 3 }
navigation
pagination = { { clickable: true } }
autoplay = { { delay: 2500 } }
loop
>
< SwiperSlide > Slide 1 </ SwiperSlide >
< SwiperSlide > Slide 2 </ SwiperSlide >
< SwiperSlide > Slide 3 </ SwiperSlide >
</ Swiper >
);
};
Swiper에 pagination을 추가하면 현재 슬라이드의 위치를 시각적으로 표시할 수 있습니다.
Pagination을 추가하는 방법은 다음과 같습니다:
Swiper 옵션에 pagination 속성을 추가합니다.
Pagination 모듈을 import합니다.
components/SwiperComponent.tsx import { Swiper , SwiperSlide } from 'swiper/react' ;
import { Pagination } from 'swiper/modules' ;
const SwiperComponent = () => {
return (
< Swiper
modules = { [ Pagination ] }
pagination = { {
clickable: true , // 페이지네이션 클릭 가능하게 설정
type: 'bullets' , // 불릿 타입으로 설정 (기본값) 'bullets', 'fraction', 'progressbar', 'custom' 중 선택
// dynamicBullets: true, // 동적 불릿 효과 적용 (선택사항)
} }
>
{ /* SwiperSlides... */ }
</ Swiper >
);
};
Pagination 옵션:
clickable: 페이지네이션 클릭 시 해당 슬라이드로 이동
type: 'bullets', 'fraction', 'progressbar', 'custom' 중 선택
dynamicBullets: 동적으로 불릿 크기가 변하는 효과 적용
추가로 페이지네이션의 스타일을 커스터마이즈하려면 CSS를 사용할 수 있습니다:
.swiper-pagination-bullet {
background : #000 ; /* 비활성 불릿 색상 */
}
.swiper-pagination-bullet-active {
background : #007aff ; /* 활성 불릿 색상 */
}
Swiper에 navigation을 추가하면 이전/다음 버튼을 추가하여 사용자가 슬라이드를 수동으로 제어할 수 있게 해줍니다.
Navigation을 추가하는 방법은 다음과 같습니다:
Swiper 옵션에 navigation 속성을 추가합니다.
Navigation 모듈을 import합니다.
components/SwiperComponent.tsx import { Swiper , SwiperSlide } from 'swiper/react' ;
import { Navigation } from 'swiper/modules' ;
const SwiperComponent = () => {
return (
< Swiper
modules = { [ Navigation ] }
navigation = { {
nextEl: '.swiper-button-next' ,
prevEl: '.swiper-button-prev' ,
} }
>
{ /* SwiperSlides... */ }
< div className = "swiper-button-next" ></ div >
< div className = "swiper-button-prev" ></ div >
</ Swiper >
);
};
Navigation 옵션:
nextEl: 다음 버튼 클래스명
prevEl: 이전 버튼 클래스명
기본적으로 Swiper는 내장된 네비게이션 버튼 스타일을 제공하지만, 커스텀 스타일을 적용하고 싶다면 다음과 같이 CSS를 사용할 수 있습니다.
.swiper-button-next ,
.swiper-button-prev {
color : #007aff ; /* 버튼 색상 */
}
.swiper-button-next:after ,
.swiper-button-prev:after {
font-size : 24px ; /* 버튼 크기 */
}
.swiper-button-disabled {
opacity : 0.35 ; /* 비활성 버튼 투명도 */
cursor : auto ;
pointer-events : none ;
}
추가로, 커스텀 아이콘이나 이미지를 사용하고 싶다면 다음과 같이 할 수 있습니다.
components/SwiperComponent.tsx const SwiperComponent = () => {
return (
< Swiper
modules = { [ Navigation ] }
navigation = { {
nextEl: '.custom-next-button' ,
prevEl: '.custom-prev-button' ,
} }
>
{ /* SwiperSlides... */ }
< button className = "custom-next-button" > 다음 </ button >
< button className = "custom-prev-button" > 이전 </ button >
</ Swiper >
);
};
기타 자세한 내용의 옵션은 `React Swiper 공식홈페이지` 를 참고하세요.
Swiper 컴포넌트 내부에 이미지 컴포넌트를 사용할 때 이미지 컴포넌트를 사용하여 이미지 최적화를 할 수 있습니다.
우선 로컬 이미지 로드시 저는 이미지를 import 방식으로 사용하는 것을 추천드립니다.
import exampleImage from './images/example.jpg' ;
제가 쓴 글 이미지 컴포넌트 가이드에 대해 확인해보세요.
`Next.js Image 컴포넌트 가이드`
import
방식을 추천하는 이유는 import 방식은 이미지 정보를 객체로 불러와서 사용하기 때문에
width와 height를 따로 지정해 줄 필요가 없으며, 하드코딩 방식으로 이미지 경로를 사용하는 방식보다 이미지 로드 파일을 분리하여 관리하기 편리합니다.
import Image from 'next/image' ;
import exampleImage from './images/example.jpg' ;
import exampleImage1 from './images/example1.jpg' ;
import exampleImage2 from './images/example2.jpg' ;
const SwiperComponent = () => {
return (
< Swiper
// .. 옵션 생략
>
< SwiperSlide >
< Image src = { exampleImage } alt = "example" />
</ SwiperSlide >
< SwiperSlide >
< Image src = { exampleImage1 } alt = "example" />
</ SwiperSlide >
< SwiperSlide >
< Image src = { exampleImage2 } alt = "example" />
</ SwiperSlide >
</ Swiper >
);
};
반복을 제거하기 위해 배열로 이미지 정보를 관리하고 map 함수를 사용하여 이미지 컴포넌트를 렌더링 할 수 있습니다.
components/SwiperComponent.tsx import Image from 'next/image' ;
import exampleImage from './images/example.jpg' ;
import exampleImage1 from './images/example1.jpg' ;
import exampleImage2 from './images/example2.jpg' ;
const images = [ exampleImage , exampleImage1 , exampleImage2 ];
const SwiperComponent = () => {
return (
< Swiper
// .. 옵션 생략
>
{ images . map (( image , index ) => (
< SwiperSlide key = { index } >
< Image src = { image } alt = "example" />
</ SwiperSlide >
)) }
</ Swiper >
);
};
한 페이지에 많은 양의 import를 사용하면 복잡해질 수 있으니 이미지 export 파일을 별도로 만들어 관리할 수도 있습니다.
images.ts import exampleImage from './example.jpg' ;
import exampleImage1 from './example1.jpg' ;
import exampleImage2 from './example2.jpg' ;
export const images = [ exampleImage , exampleImage1 , exampleImage2 ];
components/SwiperComponent.tsx import Image from 'next/image' ;
import { images } from './images' ;
const SwiperComponent = () => {
return (
< Swiper
// .. 옵션 생략
>
{ images . map (( image , index ) => (
< SwiperSlide key = { index } >
< Image src = { image } alt = "example" />
</ SwiperSlide >
)) }
</ Swiper >
);
};
이미지 컴포넌트를 사용하면 이미지가 늦게 뜨는 현상이 발생할 수 있습니다.
Next.js 이미지 컴포넌트는 기본적으로 lazy loading이 default로 설정되어 있고, lazy loading으로 인해 이미지는 화면에 나타날 때 로드되기 때문에 이미지가 늦게 뜨는 현상이 발생할 수 있습니다.
간혹 이미지가 늦게 떠서 사용자에게 이미지가 늦게 뜨는 현상이 발생할 수 있으니 loading="eager"
옵션을 사용하여 이미지를 미리 로드하도록 설정하여 이를 해결할 수 있습니다.
loading="eager"
옵션은 이미지를 미리 로드하여 사용자에게 이미지가 늦게 뜨는 현상을 해결할 수 있습니다.
< Image src = { image } alt = "example" loading = "eager" />
priority 속성은 우선적 로드를 위해 사용되는 속성이며, loading="eager"
와 함께 사용하면 더욱 빠른 이미지 로드를 기대할 수 있습니다.
단, priority 속성만 사용한다면 이미지가 늦게 뜨는 현상을 해결할 수 없습니다. 반드시 loading="eager"
옵션을 사용해야 합니다.
< Image src = { image } alt = "example" priority loading = "eager" />
next js와 swiper 슬라이드 사용시 이미지가 늦게뜨는 현상을 해결하기 위해 loading="eager"
옵션을 반드시 사용하는것이 좋습니다.
전체 코드 예시는 다음과 같습니다.
components/SwiperComponent.tsx import Image from 'next/image' ;
import { images } from './images' ;
const SwiperComponent = () => {
return (
< Swiper
// .. 옵션 생략
>
{ images . map (( image , index ) => (
< SwiperSlide key = { index } >
< Image src = { image } alt = "example" loading = "eager" />
</ SwiperSlide >
)) }
</ Swiper >
);
};
Next.js에서 이미지 컴포넌트를 사용할 때 이미지 사이즈 경고가 발생할 수 있습니다.
예를들어 Swiper 옵션 중 slidesPerView
를 사용하여 한번에 보여줄 슬라이드 수를 여러개 설정하면 이미지 사이즈 경고가 발생할 수 있습니다.
아래 이미지처럼 slidesPerView
를 4개로 설정한 경우 이미지 사이즈 경고가 발생할 수 있습니다.
Swiper 예시
이미지 sizes 옵션을 사용하지 않고 위와 같은 슬라이드 구현 시 브라우저 콘솔에 다음과 같은 경고 메세지가 나타납니다.
Image with src "이미지 주소" has "fill" but is missing "sizes" prop. Please add it to improve page performance.
이미지 사이즈 경고를 해결하기 위해 sizes
속성을 추가하여 이미지 사이즈를 지정해주어야 합니다.
< Image src = { image } alt = "example" loading = "eager" sizes = "25vw" />
sizes의 값은 viewport width 단위로 지정하며, 이미지 사이즈에 따라 적절한 값을 지정해주어야 합니다. 예시 이미지의 경우 4개의 슬라이드를 보여주기 때문에 25vw로 지정하였습니다.
만약 breakpoint에 따라 이미지 사이즈를 다르게 지정하고 싶다면 다음과 같이 media query를 사용하여 지정할 수 있습니다.
< Image
src = { image }
alt = "example"
loading = "eager"
sizes = "(max-width: 768px) 100vw, 50vw" // 768px 이하일 때 100vw, 그 이상일 때 50vw
/>
이미지 사이즈 경고를 해결하기 위해 sizes
속성을 추가하여 이미지 사이즈를 지정해주면 이미지 사이즈 경고를 해결할 수 있습니다.
그리고, sizes
속성을 사용하여 이미지 사이즈를 지정하면 브라우저가 이미지를 렌더링할 때 더욱 효율적으로 처리할 수 있어 페이지 성능을 향상시킬 수 있습니다.
이상으로 Next.js에서 React Swiper 라이브러리를 사용하는 방법과 이미지 컴포넌트를
사용하여 이미지 최적화하는 방법을 알아보았습니다.