[Next.js] 공식 문서만 보고 Next.js 익히기(2)

찐새·2023년 11월 30일
0

공식 문서만 보고

목록 보기
6/9
post-thumbnail

공식 문서 보기를 돌같이 하는 버릇을 고치자!

3. Optimizing Fonts and Images

이 장에서는 next/fontnext/image 적용과 최적화 방법을 배운다.

3-1. Why optimize fonts?

기본 폰트가 아닌 사용자 정의 폰트는 외부에서 로드하는 시간이 필요하다. 그 과정에서 Cumulative Layout Shift(CLS) 점수를 높여 나쁜 사용자 경험을 제공할 수도 있다.

Cumulative Layout Shift란, 구글에서 레이아웃 변경을 측정하는 지표이다. 요소의 이동이나 변경이 많을수록 높은 점수가 측정된다.

Next에서는 next/font를 이용해 빌드 시점에 폰트를 다운로드하여 자동 최적화한다.

3-2. Adding a primary font

next/font/google에서 Inter 폰트를 가져온다.

// app/ui/fonts.ts
import { Inter } from 'next/font/google';

export const inter = Inter({ subsets: ['latin'] });

폰트를 layoutbody에 추가하여 기본 폰트로 설정한다.

import { inter } from '@/app/ui/fonts';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${inter.className} antialiased`}>{children}</body>
    </html>
  );
}

antialiasedTailwind 코드로, 폰트를 부드럽게 처리하는 클래스이다. 멋지라고 넣었다고 한다.

3-3. Why optimize images?

이미지 파일을 수동으로 지정할 경우 다양한 부분을 고려하기 어려워 진다.

  • 다양한 화면 크기에서 이미지가 반응하는지 확인해야 한다.
  • 다양한 디바이스에 맞는 이미지 크기를 지정해야 한다.
  • 이미지 로드 시 레이아웃 이동을 방지해야 한다.
  • 사용자 뷰포트 외부에 있는 이미지를 지연 로드해야 한다.

이런 포인트를 next/image 모듈의 <Image> 컴포넌트를 이용해 자동으로 최적화한다.

  • 이미지가 로드될 때 레이아웃이 자동으로 바뀌는 것을 방지
  • 뷰포트가 작은 기기에 큰 이미지가 전송되지 않도록 이미지 크기 조정
  • 기본적으로 이미지 지연 로딩(이미지가 뷰포트에 들어올 때 로드됨)
  • 브라우저에서 지원하는 경우 WebP 및 AVIF와 같은 최신 형식의 이미지 제공
import Image from 'next/image';

export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="Screenshots of the dashboard project showing desktop version"
      />
    </div>
    //...
  );
}

이미지가 로드되는 동안 레이아웃이 변경되지 않도록 widthheight를 지정하고, 원본과 같은 비율로 설정하는 것이 좋다.

widthheight를 비율에 맞춰 자동으로 설정하려면 이미지를 import해 이미지 컴포넌트에 제공한다.

import Image from 'next/image';
import heroMobile from '../public/hero-mobile.png';

export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      <Image
        src={heroMobile}
        className="block md:hidden"
        alt="Screenshots of the dashboard project showing mobile version"
      />
    </div>
    //...
  );
}

이미지나 폰트 최적화에 관한 자세한 정보는 Image OptimizationFont Optimization를 참고한다.

4. Creating Layouts and Pages

새로운 페이지를 만드는 장이다. 파일 시스템 라우트를 사용하여 파일과 폴더의 역할과 layout을 이해하는 것이 주 목표이다.

4-1. Nested routing

파일 시스템 라우팅에서 폴더는 URL의 path에 따라 구분하는 역할을 한다. 최상위인 approot(/)를 의미하고, 하위 폴더들은 pathname을 의미한다. 즉, /로 구분되는 영역이다. 예를 들어, localhost / dashboard / invoices 경로라면, 🗂app/🗂dashboard/🗂invoices이다.

각각의 폴더는 layout.tsxpage.tsx 파일을 갖는다. page.tsx는 라우트에 해당하는 view 컴포넌트를 내보내는 역할을 한다. 🗂app/🗂dashboard/page.tsx를 만들고 localhost:3000/dashboard에 접근하면 해당 컴포넌트가 렌더링된 화면을 볼 수 있다.

🗂app/🗂dashboard/sidebar.tsx라는 파일을 만들었을 때, /dashboard/sidebar로 접근할 수 있는 게 아닌가 하는 의문이 들었다. 하지만 Next.js에서는 page와 ui 컴포넌트, 테스트 파일 등이 공존 가능한 colocation을 허용한다. 오직 page.tsx 파일이 있어야 라우트로 접근할 수 있다.

4-2. layout

layout.tsx 파일은 여러 페이지에서 같은 레이아웃을 공유하는 역할이다. layout의 이점 중 하나는 다른 페이지 컴포넌트를 업데이트할 때 layout은 리렌더링을 하지 않는다는 것이다. partial rendering이라고 부른다고 한다.

나의 실행 환경에서는 페이지 이동마다 layout도 리렌더링되던데...게다가 SPA가 아닌 MPA처럼 동작한다. 뭔가 조치가 더 필요한 건가? 약간의 의문 추가.

🗂app/layout.tsxRoot layout으로, 모든 페이지가 공유하는 필수 레이아웃이다. 여기에서 <html><body> 태그를 수정하거나 metadata를 추가할 수도 있다.

5. Navigating Between Pages

페이지 간의 이동을 다루는 장이다. 위에서 품었던 의문이 곧바로 해결되었다.

dashboard의 하위 페이지 간 이동은 <a> 태그를 이용하고 있었다. 이동마다 전체 페이지가 새로고침되는 원인이었다. next/link<Link> 컴포넌트로 대체하면 새로고침 없이 이동한다.

import Link from 'next/link';

export default function NavLinks() {
  return (
    <>
      {/* ... */}
      <Link key={link.name} href={link.href}>
        <LinkIcon className="w-6" />
        <p className="hidden md:block">{link.name}</p>
      </Link>
      {/* ... */}
    </>
  );
}

5.2 Automatic code-splitting and prefetching

Next.js는 자동으로 코드를 분할한다. 분할된 코드는 고립되었다는 의미이며, 이 페이지에서 에러가 발생해도 다른 페이지는 정상 동작한다. 또한, <Link> 컴포넌트가 동작할 때마다 백그라운드에서 라우트의 코드를 prefetch한다. 백그라운드에서 미리 로드된 목적지 페이지는 사용자가 클릭했을 때 거의 즉시 전환된다.

일반적인 UI는 현재 페이지와 같은 링크를 활성화 상태로 보여준다. 그러기 위해서 현재 pathname을 알아야 한다. next/navigationusePathname을 사용해 pathname에 접근한다.

'use client';

import { usePathname } from 'next/navigation';

훅은 Client Component에서 사용하므로 최상단에 use client를 명시해야 한다.

profile
프론트엔드 개발자가 되고 싶다

0개의 댓글