Post

Next.js 13의 특징과 변화(1)

📌시작하며

이 글은 아래와 같이 이어집니다.

Next.js 강의를 수강을 시작한지 어느정도 시간이 지났다. 내가 React를 공부하기 시작했을 때는 많은 프로젝트나 강의가 클래스형 컴포넌트에서 함수형 컴포넌트로 전환이 된 상태였던 만큼 함수형 컴포넌트에 집중할 수 있었다. 하지만 Next.js 경우 여전히 실무에서도 Next12와 Next13을 혼용해서 사용하기 때문에 강의 모두 12와 13을 다뤘고 12버전으로 작성하고 13으로 migration 하는 경우가 잦았다.

이제 개인 프로젝트를 진행하려는 시점에서 어떤 버전을 선택할지 고민이 되었고 최종적으로 Next13버전을 선택했다. 선택 이유는 다음과 같다.

  • next12 프로젝트 또한 next13으로 migration 될 거란 점
  • next13에 추가된 기능들에 대해 공부해보고 싶다는 점
  • next13의 API 작성 방식이 좀 더 직관적으로 다가왔다는 점

따라서 프로젝트 도중 12와 13버전을 혼동하지 않도록, 이번 포스팅을 통해 바뀐 점을 정리해보고자 한다.

✅use client

Next13에서는 해당 컴포넌트가 클라이언트 측에서 렌더링 할 것임을 명시해야 한다. 따라서, 아래와 같은 Hook을 사용하는 경우 상단에 use client를 작성해야 함에 주의하자.

  • useEffect
  • useState
  • useRef
  • useMemo
  • useContext

✅next/image

Next.js 13에 새로운 이미지 컴포넌트가 도입되어 레이아웃 변경 없이 이미지를 쉽게 표시하고, 파일을 최적화하여 성능을 향상시킬 수 있다.

1
2
3
4
5
6
import Image from "next/image"
import profile from "myProfile.png"

export default function Profile() {
  return <Image alt="프로필" src={profile} placeholder="blur" />
}

✅next/font

개인적으로 정말 마음에 드는 업데이트로, next/font를 통해 프로젝트에서 자주 사용하는 Google의 웹 폰트를 편리하게 사용할 수 있다. CSS 및 글꼴 파일은 빌드 시 다운로드되어 나머지 정적 에셋과 함께 자체 호스팅된다. 즉, 브라우저에서 Google에 요청을 보내지 않는다.

1
2
3
import { Inter } from "@next/font/google"
const inter = Inter()
<html className={inter.className}></html>

12.2에서 실험적으로 도입되었던 next/link가 default 값으로 변경되었다. <Link> 는 항상 <a> 태그로 render 된다.

1
2
import Link from "next/link"
;<Link href="/home">Home</Link>

✅next/navigation

useRouter 을 불러오는 경로가 달라져서 작업중에 헷갈린 경우가 있었다. 13버전 부터는 next/router가 아니라 next/navigation 으로 불러와 사용할 수 있다.

참고로 useRouter는 client components에서 사용되므로 'use client'를 작성하며, redirect는 server components에서 사용된다.

next/navigation 을 이용해 불러올 수 있는 옵션은 다음과 같다.

1
2
3
4
5
6
import {
  usePathname,
  useSearchParams,
  useRouter,
  redirect,
} from "next/navigation"

➡️usePathname

usePathname은 현재 페이지의 경로를 문자열로 반환하는 훅이다. 예를들어 다음과 같은 값을 얻을 수 있다.

URLVALUE
/'/'
/post'/post'
/post?page=3'/post'
/post/1'/post/1'
1
2
3
4
5
6
7
8
"use client"

import { usePathname } from "next/navigation"

export default function ExampleClientComponent() {
  const pathname = usePathname()
  return <p>현재 pathname: {pathname}</p>
}

➡️useSearchParams

useSearchParams는 현재 URL의 쿼리 문자열을 읽는다! 예를들어 다음과 같은 값을 얻을 수 있다. get을 통해 얻어오고, has를 통해 boolean 값을 얻을 수 있다.

URLsearchParams.get("a")
/dashboard?a=1'1'
/dashboard?a=''
/dashboard?b=3null
/dashboard?a=1&a=21
1
2
3
4
5
6
7
8
9
10
11
12
13
"use client"

import { useSearchParams } from "next/navigation"

export default function SearchBar() {
  const searchParams = useSearchParams()

  const search = searchParams.get("search")

  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>
}

➡️useRouter

useRouter는 클라이언트 컴포넌트 내에서 경로를 변경한다. 예를들어, 다음과 같은 기능을 수행할 수 있다.

형태설명
router.push(href: string, { scroll: boolean })클라이언트 측에서 수행하며, 주어진 경로로 이동한다.
brower의 history에 새로운 스택을 쌓는다.
router.replace(href: string, { scroll: boolean })클라이언트 측에서 수행하며, 주어진 경로로 이동한다.
brower의 history에 새로운 스택을 쌓지 않는다.
router.refresh()현재 경로를 새로고침한다. 서버에 새로 요청하고,
데이터 요청을 다시 가져오고, 서버 컴포넌트를 재 렌더링한다.
클라이언트는 영향을 받지 않은 클라이언트 측
React(예: useState) 또는 브라우저 상태(예: 스크롤 위치)를
잃지 않고 업데이트된 React 서버 컴포넌트 페이로드를
병합한다.
router.prefetch(href: string)더 빠른 클라이언트 측 전환을 위해 제공된 경로를 프리패치한다.
router.back()브라우저의 히스토리 스택에서 이전 경로로 돌아간다.
router.forward()브라우저의 히스토리 스택에서 다음 페이지로 이동한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
"use client"

import { useRouter } from "next/navigation"

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push("/dashboard")}>
      Dashboard
    </button>
  )
}

➡️redirect

redirect는 새로운 URL로 사용자를 리디렉션한다. 사용방식은 redirect(path, type)으로 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { redirect } from "next/navigation"

async function fetchTeam(id) {
  const res = await fetch("https://...")
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    redirect("/login")
  }

  // ...
}

📩마무리

이번 포스팅에서는 가장 간단한 변화만을 정리했다. next13의 진짜(?) 큰 변화는 app Directory의 폴더기반 라우팅이다! 그럼, 이 부분은 다음 글에서 자세하게 정리하며 익숙해져보자.

🗂️참고 사이트

This post is licensed under CC BY 4.0 by the author.