LOL 챔피언 사이트) TroubleShooting 1 : Next.js의 next/image 컴포넌트🔱

밍갱·2025년 3월 12일
0

PROJECTS

목록 보기
19/20

1. 문제 발생🤯

01. Next.js의 next/image 컴포넌트 사용하기

이번 프로젝트에서 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 컴포넌트에 대해 알아보고, 오류를 고쳐보자!

02. Taliwind CSS로 반응형 구현하기

위에서 안된게 바로 아래에서 되는 매직🪄 물론 문제해결을 위해 몇시간을 쏟았지만, 또다른 이슈를 소개하기 위해 시간을 거슬러보았다.

반응형을 해야하는 이유가 이 사진으로 설명된다. 핸드폰 스크린 사이즈로 보게되면 아이템의 이름과 설명 모두 읽기 어려워진다. 그래서 Next.js에 내장된 Taliwind CSS를 활용하여 반응형을 구현해보고자 한다.

2. 개념 정리🧐

01. Next.js의 next/image 컴포넌트와 이미지 최적화

Next.js는 next/image 컴포넌트를 제공하여 자동 이미지 최적화 기능을 지원한다. 이는 브라우저 성능을 향상시키고, 로딩 속도를 최적화하며, 다양한 디바이스에 맞춰 최적화된 이미지를 제공하는 역할을 한다.

  • 자동 포맷 변환 (WebP 지원) : Next.js는 지원하는 브라우저에 따라 이미지를 WebP 등의 고효율 포맷으로 자동 변환해준다.
  • 지연 로딩 (Lazy Loading) : 기본적으로 next/image 컴포넌트는 지연 로딩이 활성화되어 있어서, 화면에 보일 때만 이미지가 로드된다. 이를 통해 불필요한 리소스 로딩을 방지할 수 있다.
  • 반응형 이미지 : Next.js는 뷰포트 크기에 맞춰 최적화된 이미지를 자동으로 제공한다. 즉, 모바일, 태블릿, 데스크톱에서 각각 적절한 크기의 이미지가 로드되도록 도와준다.
  • CDN을 통한 이미지 최적화 : Next.js는 next/image 컴포넌트를 사용할 때 Vercel의 이미지 최적화 서비스를 기본적으로 활용하기 때문에, 별도의 서버 설정 없이도 최적화된 이미지를 빠르게 제공할 수 있다.

*WebP란? : WebP는 기존 JPG, PNG보다 용량이 작은 이미지 압축 포맷. 용량이 작아 페이지 로딩 속도를 향상시킨다.

02. next/image 컴포넌트 vs img 태그

기능<img> 태그next/image
이미지 최적화없음자동 최적화
WebP 변환수동 처리 필요지원
Lazy Loading수동 처리 필요기본 적용
반응형 지원CSS 설정 필요자동 크기 조정
CDN 최적화없음Vercel 최적화

03. next/image 컴포넌트 사용법

  • 로컬 이미지 사용 : public 폴더에 이미지를 저장하고 절대경로로 불러와야한다. 외부 URL보다 빠르고 안정적인 최적화 가능하기 때문에 가능하면 로컬 이미지를 사용하는 것이 좋다.
import Image from "next/image";

<Image
  src="/images/sample.jpg"  // 로컬 이미지 (public 폴더 내부)
  alt="Sample Image"
  width={500}  // 고정 너비
  height={300} // 고정 높이
/>
  • 외부 url 사용 : 외부 URL 이미지를 사용하려면 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}
/>

04. next/image 컴포넌트의 프로퍼티

  • 필수 프로퍼티

    • src : 이미지 경로
    • alt : 대체 텍스트, 스크린 리더 및 검색 엔진을 위해 이미지를 설명하는 데 사용
    • width : 픽셀 단위의 고유 이미지 너비
    • heigth : 픽셀 단위의 고유 이미지 높이
  • 선택 프로퍼티

    • fill : 이미지가 부모 요소를 채우도록 하는 boolean값. widthheight를 알 수 없을 때 사용(이 때, width, heigth 생략 가능)

    기타 프로퍼티들은 아래 Next.js 공식 문서 확인하기

Next.js의 next/image 컴포넌트 공식 문서
Next.js의 next/image 컴포넌트 공식 문서 (한국어판)

3. 해결 방안😇

01. Next/Image 컴포넌트에 width, heigth 프로퍼티 추가

공식 문서를 확인해보니 src, alt, width, height는 필수값인데, 나는 srcalt만 줘서 생긴 오류였던 것이다. 바로 widthheight에 임의로 50px을 넣어주었다.

01-1. 또 다른 오류발생. url 문제인가?

이건 또 뭐람? 해결된 줄 알고 설레는 마음으로 새로고침했더니, 이젠 또다른 오류가 나를 맞이했다. "대충" 읽어보니 src 프로퍼티에서 생긴 오류인 것 같다.

처음에는 이미지 url이 잘못 되었나 싶은 생각에 무작정 Riot developer 문서에 있는 url을 냅다 넣어주었다.
당연히 해결이 되지 않았다. 왜냐하면 url 문제가 아니었기 때문이다. 도대체 뭐가 문제인가 싶은 마음에 다시 오류를 꼼꼼히 읽어보았고, 이 오류에 대한 공식 문서 링크가 있어서 한번 들어가 보았다.

알고보니 Next/Image 컴포넌트에서 src에 외부 URL을 사용할 때, 해당 호스트 네임이 next.config.jsimages.remotePatterns에 등록되지 않아서 발생한 오류였다. 이래서 공식 문서를 꼼꼼히 읽어야한다는 것이다!

02. next.config.js 수정

Next/Image 컴포넌트 공식 문서에서 remotePatterns를 참고하여 next.config.js파일을 수정해주었다.

오 이미지가 페이지에 잘 불러와졌다!

02-1. grid는 어려워

개발 초기 단계이기 때문에 CSS는 최대한 간소하게 만져주었다. 동시에 반응형을 위해 grid를 사용하여 간단하게 구현해보고자 했다. 신나게 grid로 적용해주고 확인해보았더니...

왜 1줄이 되었죠?

03. grid로 반응형 구현

나는 바보 멍청이였다. Tailwind CSS 반응형 클래스를 제대로 이해하지 않고 작성하여 생긴 문제였다. max- ~로 작성된 클래스를 전부 다 수정해주었다.

그리고나서 확인해보니...

반응형이 잘 적용 되었다.

03-1. 근데 이미지 크기가 왜 다 달라요?

반응형까지 어찌저찌 해냈는데, 왜 이미지 크기는 제멋대로일까? 이 문제를 해결하고자 next/image 컴포넌트의 프로퍼티 중 fill을 활용해보았다.

next/image 컴포넌트를 <div>로 감싸줘 크기를 고정시킨 다음, fill프로퍼티를 추가해주었다.

예? 이 아름다운 오로라는 또 뭐고...

04. 제발 공식 문서를 꼼꼼히 읽어보자

이 문제 또한 공식 문서를 꼼꼼히 확인하지 않은 데에서 발생한 문제였다. 이정도면 난독증이 있는게 아닐까...🤔

알고보니 fill 프로퍼티를 사용할 때는 부모 요소에 position: absolute / relative / fixed를 주어야한다. 왜냐하면 fill 프로퍼티로 인해서 next/image 컴포넌트가 자동적으로 position: absolute가 적용되기 때문이다.

<div>position: relative를 추가해주고 다시 확인해보았다.

4. 결과😎

01. 해결!

02. 최종 코드

  • 📁items / page.tsx

  • 📁components / ItemCard.tsx

profile
미술 전공에서 프론트엔드 개발까지

0개의 댓글