이번 프로젝트에서 Next.js와 TypeScript를 사용해보게 되었다. 아직 React도 낯선데... 벌써 Next.js에다 TypeScript까지? 프로젝트 시작과 동시에 또 막막함에 의욕이 사라졌지만, 어쩌겠는가. 해야지!
이번에는 Riot Games API를 활용하여 리그 오브 레전드의 챔피언과 아이템 정보를 제공하는 사이트를 만들어야 한다. 오늘의 할 일은 "아이템 목록 페이지"를 구현하는 것이다. Riot Developer에서 아이템과 챔피온 데이터를 얻기 위해 Data Dragon 문서를 찾아보았고, 해당 데이터를 불러올 수 있는 url을 찾을 수 있었다. 아래는 item
의 이미지 경로이다.
경로를 찾아 items/itemsPage
에서 데이터를 fetch하고, UI에 next/image태그와 함께 적용해보았다.
이미지가 잘 불러와졌는지 한번 확인해보자.
역시나 오류가 없이 성공하면 밍갱의 개발새발이 아니지🫠 아래에서 Next.js의 next/image 컴포넌트에 대해 알아보고, 오류를 고쳐보자!
위에서 안된게 바로 아래에서 되는 매직🪄 물론 문제해결을 위해 몇시간을 쏟았지만, 또다른 이슈를 소개하기 위해 시간을 거슬러보았다.
반응형을 해야하는 이유가 이 사진으로 설명된다. 핸드폰 스크린 사이즈로 보게되면 아이템의 이름과 설명 모두 읽기 어려워진다. 그래서 Next.js에 내장된 Taliwind CSS를 활용하여 반응형을 구현해보고자 한다.
Next.js는 next/image 컴포넌트를 제공하여 자동 이미지 최적화 기능을 지원한다. 이는 브라우저 성능을 향상시키고, 로딩 속도를 최적화하며, 다양한 디바이스에 맞춰 최적화된 이미지를 제공하는 역할을 한다.
*WebP란? : WebP는 기존 JPG, PNG보다 용량이 작은 이미지 압축 포맷. 용량이 작아 페이지 로딩 속도를 향상시킨다.
기능 | <img> 태그 | next/image |
---|---|---|
이미지 최적화 | 없음 | 자동 최적화 |
WebP 변환 | 수동 처리 필요 | 지원 |
Lazy Loading | 수동 처리 필요 | 기본 적용 |
반응형 지원 | CSS 설정 필요 | 자동 크기 조정 |
CDN 최적화 | 없음 | Vercel 최적화 |
public
폴더에 이미지를 저장하고 절대경로로 불러와야한다. 외부 URL보다 빠르고 안정적인 최적화 가능하기 때문에 가능하면 로컬 이미지를 사용하는 것이 좋다.import Image from "next/image";
<Image
src="/images/sample.jpg" // 로컬 이미지 (public 폴더 내부)
alt="Sample Image"
width={500} // 고정 너비
height={300} // 고정 높이
/>
next.config.js
에서 도메인 허용 설정이 필요하다.// next.config.js
module.exports = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "example.com",
},
],
},
};
// 해당 컴포넌트.tsx
<Image
src="https://example.com/image.jpg"
alt="External Image"
width={600}
height={400}
/>
필수 프로퍼티
src
: 이미지 경로alt
: 대체 텍스트, 스크린 리더 및 검색 엔진을 위해 이미지를 설명하는 데 사용width
: 픽셀 단위의 고유 이미지 너비heigth
: 픽셀 단위의 고유 이미지 높이선택 프로퍼티
fill
: 이미지가 부모 요소를 채우도록 하는 boolean값. width
와 height
를 알 수 없을 때 사용(이 때, width, heigth 생략 가능)기타 프로퍼티들은 아래 Next.js 공식 문서 확인하기
Next.js의 next/image 컴포넌트 공식 문서
Next.js의 next/image 컴포넌트 공식 문서 (한국어판)
공식 문서를 확인해보니 src
, alt
, width
, height
는 필수값인데, 나는 src
와 alt
만 줘서 생긴 오류였던 것이다. 바로 width
와 height
에 임의로 50px을 넣어주었다.
이건 또 뭐람? 해결된 줄 알고 설레는 마음으로 새로고침했더니, 이젠 또다른 오류가 나를 맞이했다. "대충" 읽어보니 src
프로퍼티에서 생긴 오류인 것 같다.
처음에는 이미지 url이 잘못 되었나 싶은 생각에 무작정 Riot developer 문서에 있는 url을 냅다 넣어주었다.
당연히 해결이 되지 않았다. 왜냐하면 url 문제가 아니었기 때문이다. 도대체 뭐가 문제인가 싶은 마음에 다시 오류를 꼼꼼히 읽어보았고, 이 오류에 대한 공식 문서 링크가 있어서 한번 들어가 보았다.
알고보니 Next/Image 컴포넌트에서 src
에 외부 URL을 사용할 때, 해당 호스트 네임이 next.config.js
의 images.remotePatterns
에 등록되지 않아서 발생한 오류였다. 이래서 공식 문서를 꼼꼼히 읽어야한다는 것이다!
Next/Image 컴포넌트 공식 문서에서 remotePatterns를 참고하여 next.config.js
파일을 수정해주었다.
오 이미지가 페이지에 잘 불러와졌다!
개발 초기 단계이기 때문에 CSS는 최대한 간소하게 만져주었다. 동시에 반응형을 위해 grid
를 사용하여 간단하게 구현해보고자 했다. 신나게 grid
로 적용해주고 확인해보았더니...
왜 1줄이 되었죠?
나는 바보 멍청이였다. Tailwind CSS 반응형 클래스를 제대로 이해하지 않고 작성하여 생긴 문제였다. max- ~
로 작성된 클래스를 전부 다 수정해주었다.
그리고나서 확인해보니...
반응형이 잘 적용 되었다.
반응형까지 어찌저찌 해냈는데, 왜 이미지 크기는 제멋대로일까? 이 문제를 해결하고자 next/image 컴포넌트의 프로퍼티 중 fill
을 활용해보았다.
next/image 컴포넌트를 <div>
로 감싸줘 크기를 고정시킨 다음, fill
프로퍼티를 추가해주었다.
예? 이 아름다운 오로라는 또 뭐고...
이 문제 또한 공식 문서를 꼼꼼히 확인하지 않은 데에서 발생한 문제였다. 이정도면 난독증이 있는게 아닐까...🤔
알고보니 fill
프로퍼티를 사용할 때는 부모 요소에 position: absolute / relative / fixed
를 주어야한다. 왜냐하면 fill
프로퍼티로 인해서 next/image 컴포넌트가 자동적으로 position: absolute
가 적용되기 때문이다.
<div>
에 position: relative
를 추가해주고 다시 확인해보았다.
📁items / page.tsx
📁components / ItemCard.tsx