Next 13
Next 13
๋ฒ์ ์
์ด ๋๋ฉด์ ๊ธฐ์กด ํ๋ก์ ํธ๋ฅผ ๋ง์ด๊ทธ๋ ์ด์
ํ๋ ๊ฒฝ์ฐ Breaking Changes๋ก ์ธํด ์ ๋ฐ์ ์ผ๋ก ๋ณ๊ฒฝ์ฌํญ์ ๋ง์ถฐ ์
๊ทธ๋ ์ด๋๋ฅผ ํด์ค์ผ ํ๋ค.
Next๋ ์ด๊ฒ์ ๋ฐฉ์งํ๊ณ ์ ์๋ก ์ถ๊ฐ๋ ๊ธฐ๋ฅ๊ณผ ๊ท์น๋ค์ app/ ์ ์ ์ฉํ์ฌ ๊ธฐ์กด page/ ๊ตฌ์กฐ์  ์ฑ์ด ๋ง๊ฐ์ง์ง ์๊ณ  ์ ์ง์ ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ  ์ ์๋๋ก ์ ๊ณตํ๋ค.
Routing
app
 โโโ api
 โ   โโโ hello
 โ       โโโ route.ts
 โโโ layout.tsx
 โโโ page.tsx
 โโโ product
     โโโ [slug]
     โ   โโโ page.tsx
     โโโ layout.tsx
     โโโ page.tsx๋งค์นญํ  ๊ฒฝ๋ก๋ฅผ ํด๋ ์ด๋ฆ์ผ๋ก ๋๊ณ  ํ์์ page ์ปดํฌ๋ํธ ํ์ผ์ ๋๋ฉด ์๋์ผ๋ก ๋ผ์ฐํ
 ๋๋ค.
ํด๋(๊ฒฝ๋ก)๋ณ๋ก ๋ฒ์๋ฅผ ์ขํ ์ฌ์ฌ์ฉ๋๋ ๋ ์ด์์, ์๋ฌ ์ํ, ๋ก๋ฉ UI ๋ฑ์ ๊ณต์ ํ์ฌ ํด๋น ๋ผ์ฐํธ ์์์ ์ฒ๋ฆฌํด์ฃผ๊ธฐ ์ํจ
- page/โ- app/
- Folder & File based routing
Dynamic Routing
// app/[slug]/page.tsx
interface DynamicPageProps {
  params: {
    slug: string;
  }
}
export default function DynamicPage({ params }: DynamicPageProps) {
  
  return `slug: ${params.slug}`;
}
generateStaticParams()
generateStaticParams()์ด์  ๋ฒ์ ์ getStaticPaths() ๋ฅผ ๋์ฒดํ๋ ํจ์
๋ฏธ๋ฆฌ ์์ฑํ ํ์ด์ง์ ๋์  ๊ฒฝ๋ก(slug)๋ฅผ ์ง์ ํ๊ณ { slug: value } ๊ตฌ์กฐ์ ๋ฐฐ์ด์ ๋ฐํํ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
export function generateStaticParams() {
  const slugs = ['a', 'b'];
  return slugs.map((slug) => {
    slug,
  }) 
}Layout
- ๋ ์ด์์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฒ ์ปดํฌ๋ํธ(๋ณ๊ฒฝ ๊ฐ๋ฅ) 
- ๊ฐ์ ๊ฒฝ๋ก ๋ฐ ํ์ ๊ฒฝ๋ก์ ํ์ด์ง์ ๊ณต์ ๋๋ฉฐ ๋ํ๋๋ค. โ ๋ ์ด์์(์ปดํฌ๋ํธ) 
- ๊ฒฝ๋ก ๋ณ๋ก ๋ ์ด์์์ ์ง์  ๊ฐ๋ฅํ๋ฉฐ ์์์ ์๋ ๋ ์ด์์์ ์ค์ฒฉ๋์ด ์ ์ฉ๋๋ค. 
- ๋ฐ์ดํฐ ํจ์นญ์ด ๊ฐ๋ฅํ๋ฉฐ ๋ ์ด์์๊ฐ ์ ๋ฌ์ด ๋ถ๊ฐ๋ฅํ์ง๋ง ๊ฒฝ๋ก๊ฐ ๊ฐ์ ๊ฒฝ์ฐ ๊ฐ ๋ ์ด์์์ด ์ค๋ณต์ผ๋ก ๋ฐ์ดํฐ ํจ์นญ์ React๊ฐ ์์์ ์ค๋ณต๋ ์์ฒญ์ ์ ๊ฑฐํ๋ค. 
Root Layout (ํ์)
app/ ๋ด์์ ๊ฐ์ฅ ์์์ ์๋ layout.tsx ๋ฅผ ๋ฃจํธ ๋ ์ด์์์ด๋ผ ์นญํ๋ฉฐ ๋ชจ๋  ํ์ด์ง์ ๋ํ๋๋ค.
- ์ด์  ๋ฒ์ ์ - _app.tsx,- _document.ts ๋ฅผ ๋์ฒดํ๋ค.
- ์๋ฒ์์ ๋ฐํ๋ ์ด๊ธฐ HTML์ ์์ ํ ์ ์๋ค 
- Next.js๊ฐ ์๋์ผ๋ก - <html>,- <body>๋ฅผ ์์ฑํ์ง ์์ผ๋ฏ๋ก ๋ฃจํธ ๋ ์ด์์์ ํด๋น ํ๊ทธ๋ฅผ ์ ์ํด์ผ ํ๋ค.
Not Found Page
์ปค์คํ
 404 page๋ฅผ ๋ง๋๋ ค๋ฉด ํ์ผ์ด๋ฆ์ not-found๋ก ์ง์ ํด์ผ ํ๋ค.
ํด๋(๊ฒฝ๋ก)๋ด์ ๊ฐ์ฅ ๊ฐ๊น์ด not-found ํ์ผ์ด ์ฌ์ฉ๋์ด ํ์ด์ง ๋ณ๋ก ์๋ฌ ํ์ด์ง๋ฅผ ์ค์  ๊ฐ๋ฅ
ํ์ฌ ์์ ์๋ notFound() ํธ์ถ์ ์ํด ํธ๋ฆฌ๊ฑฐ๋  ๋๋ง ๋ ๋๋ง๋๋ค.
Global Not Found Page
ํ ์์  13.2.4 ๋ฒ์ ์์๋ Global Not Found Page ๊ธฐ๋ฅ์ด app/ ๋ผ์ฐํ
์์๋ ์์ง ์ ๊ณต๋์ง ์๊ณ  ์๋ค.
Global Not Found Page๋ฅผ ๊ตฌํํ๋ ค๋ฉด?
- ๊ธฐ์กด ๋ฐฉ์๋๋ก - page/ํ์์- 404.tsx์ปดํฌ๋ํธ๋ฅผ ์ถ๊ฐํด ์ฌ์ฉ
- app/ ๋ด์์๋์  ๋ผ์ฐํ ์ ํ์ฉํ์ฌ ๊ตฌํ
์ฐํํด์ app/ ๋ผ์ฐํ
์ผ๋ก Global Not Found Page ๊ตฌํํ๊ธฐ
์ฐํํด์ app/ ๋ผ์ฐํ
์ผ๋ก Global Not Found Page ๊ตฌํํ๊ธฐโโโ [...not-found]
โ   โโโ page.tsx
โโโ not-found.tsx// app/[...not-found]/page.tsx
import {notFound} from 'next/navigation';
export default function NotFoundCatchAll() {
  notFound();
}Metadata
์ด๋ค ํ์ด์ง(or ๋ ์ด์์)์์๋   ๊ฐ์ฒด ํํ๋ก ๋ metadata  ๋ณ์๋ฅผ export  ํด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
import type { Metadata } from 'next';
export const metadata: Metadata = {
  title: 'ํ์ดํ',
}Dynamic Metadata
generateMetadata() ํจ์๋ฅผ ํตํด ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ํจ์นญ ํ ๋ฉํ๋ฐ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
generateMetadata() ํจ์๋ฅผ ํตํด ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ํจ์นญ ํ ๋ฉํ๋ฐ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.์ฌ์ฉ์์๊ฒ ํ์ด์ง๋ฅผ ์ฃผ๊ธฐ ์  generateMetadata() ํธ์ถ๋๊ณ  ๋ฉํ๋ฐ์ดํฐ ์ ๋ณด๊ฐ ์์ฑ ๋์ด์ผ์ง๋ง ํ์ด์ง๋ฅผ ์ ์กํ๋ค.
export async function generateMetadata({ params, searchParams }) {
  const data = await getData(params); // ๋น๋๊ธฐ ๋ฐ์ดํฐ ํจ์นญ
  return { title: data.title };
}Default Metadata
๋ฐ๋ก ์ถ๊ฐํ์ง ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ค์ ๋๋ ๋ฉํํ๊ทธ
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />Rendering
๋ ๋๋ง ๋ฐฉ์์ด (page/) ํ์ด์ง ๋จ์ -> (app/) ์ปดํฌ๋ํธ ๋จ์๋ก ๋ณ๊ฒฝ๋์๋ค.
๊ธฐ์กด page ๋จ์ ๋ ๋๋ง ๋ฐฉ์์ ๋ฌธ์ ์ 
ํ์ด์ง ๋จ์์ ๋ ๋๋ง ๋ฐฉ์์ ์ฑ์ ๊ท๋ชจ๊ฐ ์ปค์ง์๋ก ํด๋ผ์ด์ธํธ๊ฐ ๋ฐ๋ ๋ฒ๋ค ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๊ฐ ์ปค์ง๋ ๋ฌธ์ ๊ฐ ์์๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด React 18 ๋ฒ์ ์ ๋ง์ถฐ ์๋ฒ ์ปดํฌ๋ํธ, ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ๊ตฌ๋ถํ์ฌ ๋ ๋๋ง ํ๋ ๋ฐฉ์์ด ๋์ ๋์๋ค.
์ปดํฌ๋ํธ ๋จ์ ๋ ๋๋ง ๋ฐฉ์์ ์ฅ์ 
ํ๋์ ํ์ด์ง ์์์ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ๊ธฐ ๋ค๋ฅธ ๋ ๋๋ง ๋ฐฉ์์ ๊ท์ ํด ์กฐํฉํ์ฌ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
์๋ฒ ์ปดํฌ๋ํธ๋ ์๋ฒ์์๋ง ์์ ์ด ์ด๋ฃจ์ด์ง๊ณ ์๋ฒ์์ ๋ ๋๋ง๋์ด ํด๋ผ์ด์ธํธ์๊ฒ ๋ณด๋ผ ์ฝ๋๊ฐ ์๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ๊ฐ ๋ฐ์ ๋ฒ๋ค ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๊ฐ ํ์ ํ ์ค์ด๋ค๊ฒ ๋๋ค.
์ฆ, ์ฌ์ฉ์์ ์ธํฐ๋ ์ ์ด ํ์ํ ์ฝ๋๋ง ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋์ด ์ด๊ธฐ ๋ก๋ฉ ์๋๊ฐ ๋์ฑ ๋นจ๋ผ์ง๊ฒ ๋๋ค.
React v18์์ ์๋กญ๊ฒ ์ถ๊ฐ๋ ๊ธฐ๋ฅ
์๋ฒ์์์ ๋ฆฌ์กํธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ๋์๋ค.
- ์๋ฒ์์์๋ง ๋์ํ๋ ์ปดํฌ๋ํธ 
- SSR !== RSC, ์๋ก ๋์ฒด์ ๊ฐ ์๋๋ฉฐ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๊ธฐ ์ํด ์๋ก ๋ณด์ํ์ฌ ์ฌ์ฉ๋๋ ๊ฒ - ํ๋ฆฌ ๋ ๋๋ง(SSR) + ๋ฒ๋ค์ฌ์ด์ฆ ์ต์ํ(RSC) 
 
- app/๋ด์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฒ ์ปดํฌ๋ํธ์ด๋ค.
- ์๋ฒ์์ ๋น๋ ๋ ๋ ์คํ๋๋ ์ปดํฌ๋ํธ, ๊ธฐ๋ณธ์ ์ผ๋ก SSG 
- ์ ์ ์ธ HTML ํํ๋ก ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋๋ฉฐ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ Zero 
- ๋ธ๋ผ์ฐ์ ์์ ์ ๊ณตํ๋ API, Hooks๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง node.js(์๋ฒ)์์ ์ ๊ณตํ๋ API๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. 
- ์๋ฒ ์ปดํฌ๋ํธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ๋ ์ ์ญ ์ฑ๊ธํค๊ณผ ๊ฐ์ ๋ค์ดํฐ๋ธ ์๋ฐ์คํฌ๋ฆฝํธ ํจํด์ ํ์ฉ 
- ์๋ฒ ์ปดํฌ๋ํธ ๊ฐ์ ์๋ฒ(DB)์์ ํจ์นญํ ๋ฐ์ดํฐ ์์์ ๊ณต์ ํ๊ณ ์ถ์ ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ถํ์ํ๊ฒ ์ ๋ฌํ ํ์ ์์ด ๊ทธ ๋ฐ์ดํฐ๋ฅผ ํ์๋ก ํ๋ ๊ณณ์์ ํจ์นญํ๋ฉด ๋๋ค. ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ ์บ์ฑ ๋์ด ๋ฅ์คํธ์์ ์ค๋ณต ์์ฒญ์ ์ ๊ฑฐํ๋ ์์ผ๋ก ์ต์ ํ๊ฐ ์๋์ผ๋ก ์ด๋ฃจ์ด์ง๋ค. 
Client Component
์ด์  ๋ฒ์ ์์ ์ฌ์ฉํ๋ ํ๋ฆฌ๋ ๋๋ง + ํ์ด๋๋ ์ด์  ๋ฐฉ์
- ๋ํดํธ๊ฐ ์๋ฒ์ปดํฌ๋ํธ์ด๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์๋จ์ - use client๋ฅผ ๋ช ์ํด์ฃผ์ด์ผ ํ๋ค.
- ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ผ๊ณ ํด์ ๋ฌด์กฐ๊ฑด - csr๋ก ๋์ํ๋ ๊ฒ์ด ์๋๋ค.
- ์๋ฒ์์ ์ปดํฌ๋ํธ๋ฅผ ์ฝ๊ณ ์ ์ ์ธ ๋ถ๋ถ์ ๋ถ๋ฆฌํ์ฌ ํ๋ฆฌ๋ ๋๋ง์ ํฌํจ์ํค๊ณ ํ์ด๋๋ ์ด์  ๊ณผ์ ์ด ์ผ์ด๋๋ค. (๊ธฐ์กด ๋ฐฉ์๊ณผ ๋์ผ) 
- ์ฌ์ฉ์์ ์ด๋ฒคํธ๊ฐ ์๊ฑฐ๋ ๋ธ๋ผ์ฐ์ ์์ ์คํ๋์ด์ผ ํ๋ ์ฝ๋๋ค์ด ์๋ค๋ฉด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ด๋ค. 
- ์ฆ, ์ฌ์ฉ์(๋ธ๋ผ์ฐ์ )์๊ฒ ๋ณด๋ด์ ธ์ผ ํ๋ ์ฝ๋๋ค์ด ๋ด๊ธด ์ปดํฌ๋ํธ 
- ์ํ๋ฅผ ์ฐ๊ฑฐ๋ hooks๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ฌ์ฉํด์ผ ํ๋ค. 
- ์๋ฒ ์ปดํฌ๋ํธ์์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํ๋ props๋ serialization(์ง๋ ฌํ)๊ฐ ๊ฐ๋ฅํด์ผ ํ๋ค. 
- ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ์ฌ์ฉ๋๋ ๋ชจ๋, ํ์ ์ปดํฌ๋ํธ๋ค์ ๋ชจ๋ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๊ฐ ๋๋ค. - ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ์๋ฒ ์ปดํฌ๋ํธ๋ฅผ ์ํฌํธํด์ ์ฌ์ฉํ ์ ์๋ค. 
- ๋ฐ๋ผ์ ๊ฐ๋ฅํ๋ค๋ฉด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ ์ปดํฌ๋ํธ Tree์์ ๊ฐ์ฅ ๋๋จ์ ์์นํ๋ leaf๋ก ์ด๋์ํค๋ ๊ฒ์ด ์ข๋ค. 
- ๋ถ๊ฐํผํ ๊ฒฝ์ฐ ๋ฅ์คํธ์์ ์ปดํฌ์ง์  ํจํด(์์ ์ปดํฌ๋ํธ๋ฅผ props๋ก ์ ๋ฌํ์ฌ ์์ ์ปดํฌ๋ํธ๋ฅผ ์กฐํฉํ๋ ํจํด)์ ํ์ฉํ ๊ฒ์ ๊ถ๊ณ ํ๋ค. 
 
์๋ฒ ์ปดํฌ๋ํธ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ ๊ตฌ๋ถํ๊ธฐ
์ฌ์ฉ์์๊ฒ ์ ๋ฌ ๋์ด์ผ ํ๋ ์ฝ๋๊ฐ ํฌํจ๋ ๊ฒฝ์ฐ๋ง ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ๋ง๋ค์ด ์ฑ๋ฅ์ ๋์ด์.
๋ฐ์ดํฐ ํจ์นญ
โ
๋ฐ์ดํฐ ํจ์นญ์ด ๊ฐ๋ฅํ์ง๋ง ํน๋ณํ ์ด์ ๊ฐ ์๋ค๋ฉด ์๋ฒ์์ ๋ฐ์ดํฐ ํจ์นญ์ ํ๋ ๊ฒ์ด ์ข๋ค. (์ฑ๋ฅ, ์ฌ์ฉ์ฑ)
๋ฐฑ์๋ ๋ฆฌ์์ค ์ง์  ์ ๊ทผ
โ
โ
๋ ธ์ถ๋๋ฉด ์๋๋ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ(์์ธ์ค ํ ํฐ, API Keys)
โ
โ
์ฌ์ฉ์์ ์ํธ์์ฉํ๋ ์ฝ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ฌ์ฉ
โ
โ
React Hooks ์ฌ์ฉ (useState, useEffect ๋ฑ)
โ
โ
๋ธ๋ผ์ฐ์  API ์ฌ์ฉ
โ
โ
Data Fetching
getStaticProps(),gstServerSideProps()๋ฅผ ๋์ฒดํ๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ์์ด ์ถ๊ฐ ๋์๋ค.
์ด๋ ์์ ์ ํ์ด์ง(or ๋ ์ด์์)๋ฅผ ์ฌ์์ฑ ํ ์ง ์ง์ 
revalidate
๋ธ๋ผ์ฐ์ ์์ ํ์ด์ง(or ๋ ์ด์์)์ ์ฌ๊ฒ์ฆํ๋ ๊ธฐ๋ณธ ์๊ฐ์ ์ง์ 
export const revalidate = false; // default
// false(SSG) | 'force-cache'(SSG) | 0(SSR) | number(ISR)fetch() ์ ์ค์ ๋ ์บ์ ์ต์
์ override ํ์ง ์๋๋ค.
-> revalidate < fetch()
fetch(url, options)
async/await์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ํจ์นญ
Next.js๋ Web fetch API๋ฅผ ํ์ฅํ์ฌ ์ฌ์ฉ
์บ์ ์ ๋ฌด์ ๋ฐ๋ผ SSG, ISR, SSR ๋ก ๋๋๊ฒ ๋๋ค.
export default async function Page() {
  const data = await fetch(url, {
    cache: 'force-cache'; // default (SSG)
    // no-store(SSR), number(ISR)
  });
}Dynamic Rendering
๋์  ํจ์ ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ fetch() ์์ฒญ์ ์บ์ ์ต์
์ด no-store ์ผ ๋ ๋์  ๋ ๋๋ง(SSR)์ผ๋ก ์ ํ๋๋ค.
๋์  ํจ์(Dynamic fuction)
์ฌ์ฉ์์ ์์ฒญ ์์ ์ ์ ์ ์๋ ์ ๋ณด๋ฅผ ์ฌ์ฉํ ํจ์๋ฅผ ๋์  ํจ์๋ผ ํ๋ค.
ex) ์์ฒญ ์์ ์ ์ ์ ์๋ ์ ๋ณด -> ์ฟ ํค, HTTP ์์ฒญ ํค๋, URL params
API Route
Next๊ฐ Full Stack์ผ๋ก ๊ฐ๋ฐํ ์ ์๋ ์ด์
์์ฒญ ๋ณ(Get, Post)๋ก ๋๋์ด ๊ตฌ์กฐ์ ์ผ๋ก ๊ตฌํ ๊ฐ๋ฅํ๋๋ก ๋ฐ๋์๋ค.
// app/api/[endpoint]/route.ts
export async function GET(req: Request) {
  const data = await ...
  return NextResponse.json(data);
}๋ผ์ฐํธ๋น ํด๋ ํ๋
๋ผ์ฐํธ๊ฐ ๋๋ ํด๋ ์ฆ, ํ์ด์ง ๋ณ๋ก ๋ค์ํ๊ณ ์ ์ฉํ ์์ดํ ๋ค์ ์ค์ ํ ์ ์๋ค.
ํด๋ ๋ณ๋ก ์ค์ ํ  ์ ์๋ ํญ๋ชฉ๋ค
- page.tsx: ํด๋น ํด๋๋ฅผ ๊ฒฝ๋ก๋ก ํ๋ ํ์ด์ง ์ปดํฌ๋ํธ 
- layout.tsx: ํ์ด์ง๋ฅผ ๊ฐ์ธ๋ ๊ณจ๊ฒฉ์ ์ค์  (์์ ๋ ์ด์์์ ์ค์ฒฉ๋จ) 
- template.tsx: ๋ ์ด์์๊ณผ ๋น์ทํ๋. ํ์ด์ง ์ ํ์ ์ปดํฌ๋ํธ์ ์ ์ธ์คํด์ค๊ฐ ๋ง์ดํธ๋์ด ์คํ๋๋ ์ฐจ์ด๊ฐ ์๋ค. 
- loading.tsx: ํด๋น ๋ผ์ฐํธ์์ ํ์ด์ง UI๊ฐ ์ค๋น๋๊ธฐ ์  ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ฃผ๋ UI ์ปดํฌ๋ํธ (React.Suspense) 
- error.tsx: ๋ฐํ์ ์๋ฌ์ ๋์ฒด UI ์ปดํฌ๋ํธ (React.ErrorBoundary) 
- not-found.tsx: ํด๋น ๋ผ์ฐํธ์ 404 UI ์ปดํฌ๋ํธ 
loading.tsx
ํด๋น ๋ผ์ฐํธ์ ํ์ด์ง๊ฐ ์ค๋น๋๋ ๋์ loading.tsx์ ์ ์ธํ ์ปดํฌ๋ํธ๊ฐ ๋ณด์ฌ์ง๊ฒ ๋๋ค. * layout์ ์ ์ธํ page ๋ถ๋ถ๋ง ์ ์ฉ๋จ
์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ด๋ถ์ ์ผ๋ก React.Suspense ๋ฅผ ์ฌ์ฉํ๋ค.
<Layout>
  <Suspense fallback={<Loading />}>
    <Page />
  </Suspense>
</Layout>๋ก๋ฉ์ ๋์ ์ธ SSR์ ํ ๋ ๋น ๋ฅด๊ฒ ๋ก๋ฉ UI๋ฅผ ๋จผ์  ๋ณด์ฌ์ฃผ๊ณ ์ค์  ์ปดํฌ๋ํธ๋ฅผ ๋ณ๋ ฌ์ ์ผ๋ก ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํํ ์๋ฃ๋๋ฉด ์ ์กํ๋ ์์ผ๋ก ์ฌ์ฉ์์๊ฒ ํ์ด์ง๊ฐ ์๋น์ค์ด๋ผ๋ ๊ฒ์ ์๋ฆฐ๋ค.
ํ๊ณ์ 
ํด๋น ์ปดํฌ๋ํธ๋ ํ์ด์ง ์ ์ฒด๋ฅผ ๋ฌถ๊ธฐ ๋๋ฌธ์ ๋ณ๋ ฌ ์คํธ๋ฆฌ๋ฐ์ ์ํด์๋ ๋ด๋ถ ์์๋ค์ ์์คํ์ค๋ฅผ ๋ฐ๋ก ์ค์  ํด์ค์ผ ํ๋ค.
Suspense ์ฌ์ฉ ์ด์ 
UI๋ฅผ ๋ ๋๋งํ๊ธฐ ์ ์ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ๋ก๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆด ํ์ ์์ด ํ์ด์ง์ ์ผ๋ถ๋ฅผ ๋ ๋นจ๋ฆฌ ํ์ํ ์ ์๋ค.
- Streaming Server Rendering: ์คํธ๋ฆฌ๋ฐ์ ์ฌ์ฉํ๋ฉด ํ์ด์ง์ HTML์ ๋ ์์ ์ฒญํฌ๋ก ๋๋๊ณ ํด๋น ์ฒญํฌ๋ฅผ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ์ ์ง์ ์ผ๋ก ์ ์กํ ์ ์์ต๋๋ค 
- Selective Hydration: ์ฌ์ฉ์ ์ธํฐ๋ ์ ์ ํตํด ์ด๋ค ์ปดํฌ๋ํธ๋ฅผ ๋จผ์  ์ํํ ์ง ์ ํ์ ์ผ๋ก ๊ฒฐ์  
error.tsx
์๋ฌ ์ปดํฌ๋ํธ๋ ์ด๋ค ์๋ฌ๊ฐ ๋ฐ์ํ๋์ง์ ํ์ด์ง๋ฅผ ๋ฆฌ์ ํ ์ ์๋ ์ฝ๋ฐฑํจ์๋ฅผ props๋ก ์ ๊ณตํ๋ค.
๋ด๋ถ์ ์ผ๋ก ErrorBoundary ๋ฅผ ์ฌ์ฉํ๋ค.
<Layout>
  <ErrorBoundary fallback={<Error />}>
    <Page />
  </ErrorBoundary>
</Layout>์๋ฌ ์ปดํฌ๋ํธ๋ ๋ฐํ์์ ํ์ํ ์ฌ์ฉ์ ์ฝ๋์ useEffect ๊ฐ์ ํ
๋ค์ ์ฌ์ฉํด์ผ ํ๋ ๋ฌด์กฐ๊ฑด Client ์ปดํฌ๋ํธ๊ฐ ๋๋ค.
loading.tsx ์ ๋ง์ฐฌ๊ฐ์ง๋ก ํ์ด์ง ๋ด๋ถ ์์ ๋จ์๋ก ์๋ฌ UI๋ฅผ ๋ณด์ฌ์ฃผ๊ณ  ์ถ๋ค๋ฉด ํด๋น ์ปดํฌ๋ํธ๋ฅผ ErrorBoundary๋ก ๊ฐ์ธ๋ฉด ๋๋ค.
๊ฐ์ฅ ๊ทผ์ ํ ๋ถ๋ชจ์ error.tsx ๋ฅผ ๋ณด์ฌ์ค๋ค. (๋ฒ๋ธ๋ง ๋จ)
Last updated
