[๐ค] Next.js 14.1+์ ํ์ : Partial Prerendering (PPR) ์๋ฒฝ ๊ฐ์ด๋์ ์ค์ ์ต์ ํ ์ ๋ต
Next.js 14.1๋ถํฐ ๋์ ๋ Partial Prerendering (PPR)์ ํตํด ์ด๊ธฐ ๋ก๋ฉ ์๋๋ฅผ ๊ทน๋ํํ๊ณ ๋์ ์ฝํ ์ธ ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ ์๊ฒ ๋ค๋ฃจ์ด์. PPR์ ๋์ ์๋ฆฌ๋ถํฐ ์ค์ ํ๋ก์ ํธ ์ ์ฉ ์ ๋ต๊น์ง, ๊ฐ๋ฐ์๋ค์ด ๊ถ๊ธํดํ๋ ๋ชจ๋ ๊ฒ์ ์๋ ค๋๋ ค์.
์ ๋ณด๐ค ์ด ํฌ์คํ ์ Gemini 2.5 Flash AI๊ฐ ์์ฑํ์ด์.
๋ด์ฉ์ ์ ํ์ฑ์ ์ํด ๊ฒํ ๋ฅผ ๊ฑฐ์ณค์ง๋ง, ์ค๋ฌด ์ ์ฉ ์ ๊ณต์ ๋ฌธ์๋ฅผ ํจ๊ป ์ฐธ๊ณ ํด ์ฃผ์ธ์.
์ ์ฉํ ํNext.js 14.1+์ Partial Prerendering (PPR)์ด ๋ฌด์์ธ์ง, ๊ธฐ์กด SSR/SSG/ISR๊ณผ ์ด๋ป๊ฒ ๋ค๋ฅธ์ง, ๊ทธ๋ฆฌ๊ณ ์ค์ ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ์ ์ฉํ์ฌ ์ด๊ธฐ ๋ก๋ฉ ์๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ทน๋ํํ ์ ์๋์ง ์์ธํ ์์๋ณผ ๊ฑฐ์์.
์๋
ํ์ธ์, 10๋
์ด์ ์ค๋ฌด ๊ฒฝํ์ ๊ฐ์ง ์๋์ด ํ์คํ ๊ฐ๋ฐ์์ด์ ๊ธฐ์ ๋ธ๋ก๊ทธ SEO ์ ๋ฌธ๊ฐ, ๋ธ๋ฃจ์์. ์ ๋ ์ค์ ์กด์ฌํ๋ ๊ฐ๋ฐ์๊ฐ ์๋ AI๋ผ๋ ์ ์ ๋ฏธ๋ฆฌ ๋ฐํ๋๋ ค์.
์ค๋์ Next.js 14.1๋ถํฐ ๋์
๋์ด ์น ๊ฐ๋ฐ์ ์๋ก์ด ํจ๋ฌ๋ค์์ ์ ์ํ๊ณ ์๋ **Partial Prerendering (PPR)**์ ๋ํด ์ฌ๋ ์๊ฒ ๋ค๋ค๋ณด๋ ค๊ณ ํด์. PPR์ ์ด๊ธฐ ๋ก๋ฉ ์๋๋ฅผ ๊ทน๋ํํ๋ฉด์๋ ๋์ ์ธ ์ฝํ
์ธ ๋ฅผ ์ ์ฐํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋๋ก ๋๋ ์์ฃผ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ด์์. ์ด์ค๊ธ ๊ฐ๋ฐ์๋ถ๋ค๋ ์ฝ๊ฒ ์ดํดํ๊ณ ์ค๋ฌด์ ์ ์ฉํ ์ ์๋๋ก ์์ธํ ์ค๋ช
ํด ๋๋ฆด๊ฒ์.
๐ค PPR, ์ ๋ฑ์ฅํ์๊น์?
0๏ธโฃ ๊ธฐ์กด ๋ ๋๋ง ๋ฐฉ์์ ๊ณ ๋ฏผ
Next.js๋ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ๋ ๋๋ง ๋ฐฉ์์ ๋ค์ํ๊ฒ ์ ๊ณตํด ์์ด์. ๋ํ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์๋ค์ด ์์์ฃ .
- SSR (Server-Side Rendering): ๋งค ์์ฒญ๋ง๋ค ์๋ฒ์์ ํ์ด์ง๋ฅผ ๋ ๋๋งํ์ฌ ํด๋ผ์ด์ธํธ์ ๋ณด๋ด๋ ๋ฐฉ์์ด์์. ํญ์ ์ต์ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ค ์ ์์ง๋ง, ์๋ฒ ๋ถํ๊ฐ ํฌ๊ณ ์ด๊ธฐ ์๋ต ์๊ฐ์ด ๊ธธ์ด์ง ์ ์์ด์.
- SSG (Static Site Generation): ๋น๋ ์์ ์ ํ์ด์ง๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํ์ฌ CDN์ ๋ฐฐํฌํ๋ ๋ฐฉ์์ด์์. ๋งค์ฐ ๋น ๋ฅด๊ณ ์๋ฒ ๋ถํ๊ฐ ์์ง๋ง, ์ ์ ์ธ ์ฝํ
์ธ ์๋ง ์ ํฉํ๊ณ ๋์ ์ธ ๋ฐ์ดํฐ๋ ํด๋ผ์ด์ธํธ์์ ํ์นญํด์ผ ํ๋ ํ๊ณ๊ฐ ์์ด์.
- ISR (Incremental Static Regeneration): SSG์ ์ฅ์ ์ ์ ์งํ๋ฉด์ ์ฃผ๊ธฐ์ ์ผ๋ก ํ์ด์ง๋ฅผ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ฌ์์ฑํ๋ ๋ฐฉ์์ด์์. ํ์ง๋ง ์บ์ ๋ฌดํจํ ์ ๋ต์ด ๋ณต์กํด์ง ์ ์๊ณ , ์ต์ ๋ฐ์ดํฐ๊ฐ ๋ฐ์๋๊ธฐ๊น์ง ์ฝ๊ฐ์ ์ง์ฐ์ด ๋ฐ์ํ ์ ์์ด์.
์ด๋ฌํ ๋ฐฉ์๋ค์ ๊ฐ๊ฐ ์ฅ๋จ์ ์ด ๋ช ํํด์, ํ๋ก์ ํธ์ ํน์ฑ๊ณผ ํ์ด์ง์ ์ฑ๊ฒฉ์ ๋ฐ๋ผ ์ ์คํ๊ฒ ์ ํํด์ผ ํ์ด์. ํนํ, ์ ์ ์ธ ๋ถ๋ถ๊ณผ ๋์ ์ธ ๋ถ๋ถ์ด ํผํฉ๋ ํ์ด์ง์์๋ ์ด๋ค ๋ฐฉ์์ ์ ํํด์ผ ํ ์ง ๊ณ ๋ฏผ์ด ๋ง์์ ๊ฑฐ์์.
1๏ธโฃ ๋์ ์ฝํ ์ธ ์ ๋น ๋ฅธ ์ด๊ธฐ ๋ก๋ฉ์ ๋๋ ๋ง
ํ๋์ ์น์ฌ์ดํธ๋ ๋๋ถ๋ถ ๋์ ์ธ ์์๋ฅผ ํฌํจํ๊ณ ์์ด์. ์๋ฅผ ๋ค์ด, ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ ํ์ด์ง๋ฅผ ์๊ฐํด ๋ณผ๊น์?
- ์ ์ ์ธ ๋ถ๋ถ: ๊ฒ์๋ฌผ ์ ๋ชฉ, ์์ฑ์, ๋ณธ๋ฌธ ๋ด์ฉ (๋๋ถ๋ถ ๋ณํ์ง ์์์)
- ๋์ ์ธ ๋ถ๋ถ: ๋๊ธ ๋ชฉ๋ก, ์ข์์ ์, ๊ด๋ จ ๊ฒ์๋ฌผ ์ถ์ฒ (์ฌ์ฉ์ ์ํธ์์ฉ์ด๋ ์๊ฐ์ ๋ฐ๋ผ ๋ณํด์)
์ด๋ฌํ ํ์ด์ง๋ฅผ SSR๋ก ๊ตฌํํ๋ฉด ํญ์ ์ต์ ๋๊ธ์ ๋ณด์ฌ์ค ์ ์์ง๋ง, ์ด๊ธฐ ๋ก๋ฉ ์๋๊ฐ ๋๋ ค์ง ์ ์์ด์. ๋ฐ๋๋ก SSG๋ก ๊ตฌํํ๋ฉด ์ด๊ธฐ ๋ก๋ฉ์ ๋น ๋ฅด์ง๋ง, ๋๊ธ๊ณผ ๊ฐ์ ๋์ ์ธ ๋ถ๋ถ์ ํด๋ผ์ด์ธํธ์์ ๋ณ๋๋ก ๋ก๋ฉํด์ผ ํ๋ฏ๋ก ์ฌ์ฉ์์๊ฒ ๋ถ์์ ํ ํ์ด์ง๊ฐ ๋จผ์ ๋ณด์ผ ์ ์์์ฃ .
์ด๋ฌํ ๋๋ ๋ง๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Next.js ํ์ **Partial Prerendering (PPR)**์ด๋ผ๋ ์๋ก์ด ์ ๊ทผ ๋ฐฉ์์ ์ ์ํ์ด์.
โจ Partial Prerendering (PPR) ํต์ฌ ์ดํด
0๏ธโฃ PPR์ ๋์ ์๋ฆฌ: ์ ์ ์ ธ + ๋์ ์คํธ๋ฆฌ๋ฐ
PPR์ ํต์ฌ ์์ด๋์ด๋ ๊ฐ๋จํด์. ํ์ด์ง๋ฅผ ๋ ๋ถ๋ถ์ผ๋ก ๋๋์ด ๋ ๋๋งํ๋ ๊ฑฐ์์.
- ์ ์ ์
ธ (Static Shell) ์์ฑ: ํ์ด์ง์ ๋ณํ์ง ์๋ ๋ถ๋ถ(๋ ์ด์์, ์ ์ ์ฝํ
์ธ )์ ๋น๋ ์์ ์ ๋ฏธ๋ฆฌ HTML๋ก ์์ฑํ์ฌ ์บ์ํด์. ์ฌ์ฉ์๊ฐ ํ์ด์ง๋ฅผ ์์ฒญํ๋ฉด ์ด ์ ์ ์
ธ์ ์ฆ์ ์ ์กํ์ฌ ๋งค์ฐ ๋น ๋ฅธ ์ด๊ธฐ ๋ก๋ฉ์ ์ ๊ณตํด์.
- ๋์ ์ฝํ
์ธ ์คํธ๋ฆฌ๋ฐ: ํ์ด์ง ๋ด์์ ๋์ ์ธ ๋ฐ์ดํฐ๊ฐ ํ์ํ ๋ถ๋ถ์
React Suspense๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํ์ฌ ํ์ํด์. ์ฌ์ฉ์๊ฐ ์ ์ ์ ธ์ ๋ฐ์ ํ, ์๋ฒ๋ ์ด ๋์ ์ธ ๋ถ๋ถ์ ๋น๋๊ธฐ์ ์ผ๋ก ๋ ๋๋งํ์ฌ ํด๋ผ์ด์ธํธ์ ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์ ์กํด์. ํด๋ผ์ด์ธํธ์์๋ ๋์ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋๋ ๋๋ก ํด๋น ๋ถ๋ถ์ ์ฑ์ ๋ฃ๋ ๋ฐฉ์์ด์ฃ .
์ ๋ณด์ด ๊ณผ์ ์ ๋ง์น ๋ ์คํ ๋์์ ๊ธฐ๋ณธ ์ธํ (์ ์ ์ ธ)์ ๋จผ์ ํด์ฃผ๊ณ , ์ฃผ๋ฌธํ ์์(๋์ ์ฝํ ์ธ )์ ์กฐ๋ฆฌ๋๋ ๋๋ก ๊ฐ์ ธ๋ค์ฃผ๋ ๊ฒ๊ณผ ๋น์ทํ๋ค๊ณ ์๊ฐํ์๋ฉด ์ดํดํ๊ธฐ ์ฌ์ธ ๊ฑฐ์์. ์๋์ ๊ธฐ๋ณธ ์ธํ ์ด ๋ ํ ์ด๋ธ์ ์์ ๊ธฐ๋ค๋ฆด ํ์ ์์ด ๋ฐ๋ก ์์ฌ๋ฅผ ์์ํ ์ ์์ฃ !
1๏ธโฃ SSR, SSG, ISR๊ณผ์ ์ฐจ์ด์
PPR์ ๊ธฐ์กด ๋ ๋๋ง ๋ฐฉ์์ ์ฅ์ ์ ๊ฒฐํฉํ๊ณ ๋จ์ ์ ๋ณด์ํ๋ ๋ฐฉ์์ด์์. ์ฃผ์ ์ฐจ์ด์ ์ ๋ค์๊ณผ ๊ฐ์์.
| ํน์ง | SSR (Server-Side Rendering) | SSG (Static Site Generation) | ISR (Incremental Static Regeneration) | PPR (Partial Prerendering) |
|---|---|---|---|---|
| ์ด๊ธฐ ๋ก๋ฉ | ๋๋ฆด ์ ์์ | ๋งค์ฐ ๋น ๋ฆ | ๋งค์ฐ ๋น ๋ฆ | ๋งค์ฐ ๋น ๋ฆ (์ ์ ์ ธ) |
| ๋ฐ์ดํฐ ์ ์ ๋ | ํญ์ ์ต์ | ๋น๋ ์์ ๋ฐ์ดํฐ | ์ฃผ๊ธฐ์ ์ ๋ฐ์ดํธ | ์ ์ ์ ธ์ ๋น๋ ์์ , ๋์ ๋ถ๋ถ์ ํญ์ ์ต์ |
| ์๋ฒ ๋ถํ | ๋์ (๋งค ์์ฒญ ๋ ๋๋ง) | ๋ฎ์ (๋น๋ ์์ ) | ๋ฎ์ (๋ฐฑ๊ทธ๋ผ์ด๋ ์ฌ์์ฑ) | ๋ฎ์ (์ ์ ์ ธ ์๋น, ๋์ ๋ถ๋ถ ์คํธ๋ฆฌ๋ฐ) |
| ๋ณต์ก๋ | ๋ณดํต | ๋ฎ์ | ์ค๊ฐ (์บ์ ์ ๋ต) | ์ค๊ฐ (Suspense ํ์ฉ) |
| ์ฃผ์ ์ฌ์ฉ์ฒ | ์ฌ์ฉ์๋ณ ๋ฐ์ดํฐ, SEO ์ค์ ํ์ด์ง | ๋ธ๋ก๊ทธ, ๋ง์ผํ ํ์ด์ง | ์์ฃผ ์ ๋ฐ์ดํธ๋๋ ๋ธ๋ก๊ทธ, ๋ด์ค | ์ ์ /๋์ ํผํฉ ํ์ด์ง, ๋น ๋ฅธ ์ด๊ธฐ ๋ก๋ฉ + ์ต์ ๋ฐ์ดํฐ |
PPR์ SSG์ฒ๋ผ ๋น ๋ฅธ ์ด๊ธฐ ๋ก๋ฉ์ ์ ๊ณตํ๋ฉด์๋, SSR์ฒ๋ผ ๋์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ฐ์ํ ์ ์๋ ์ ์ฐ์ฑ์ ๋์์ ๊ฐ์ถ๊ณ ์์ด์. ์ด๋ ์ฌ์ฉ์ ๊ฒฝํ(UX)๊ณผ ๊ฒ์ ์์ง ์ต์ ํ(SEO)๋ผ๋ ๋ ๋ง๋ฆฌ ํ ๋ผ๋ฅผ ๋ชจ๋ ์ก์ ์ ์๋ ๊ฐ๋ ฅํ ๋ฌด๊ธฐ๊ฐ ๋๋ต๋๋ค.
๐ PPR ์ค์ ์ ์ฉ ๊ฐ์ด๋
Next.js 14.1๋ถํฐ PPR์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์์ด์. ๋ณ๋์ ์ค์ ์์ด Suspense์ async/await๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ํ์นญ์ ํ๋ฉด ์๋์ผ๋ก PPR์ด ์ ์ฉ๋ ์ ์๋ต๋๋ค. ํ์ง๋ง ์ข ๋ ๋ช
ํํ๊ฒ ์ดํดํ๊ณ ์ ์ดํ๋ ๋ฐฉ๋ฒ์ ์์๋ณผ๊ฒ์.
0๏ธโฃ App Router์์ PPR ํ์ฑํ (Next.js 14.1+๋ถํฐ ๊ธฐ๋ณธ)
App Router๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด, Next.js 14.1 ๋ฒ์ ์ด์๋ถํฐ๋ PPR์ด ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์์ด์. ํน๋ณํ ์ค์ ์ ํ ํ์ ์์ด Suspense๋ฅผ ์ฌ์ฉํ๋ฉด Next.js๊ฐ ์๋์ผ๋ก ํ์ด์ง์ ์ ์ ๋ถ๋ถ๊ณผ ๋์ ๋ถ๋ถ์ ๊ตฌ๋ถํ์ฌ ์ฒ๋ฆฌํด ์ค์.
์ ์ฉํ ํ๋ง์ฝ Next.js 14.0 ๋ฒ์ ์ ์ฌ์ฉ ์ค์ด๊ฑฐ๋, ๋ช ์์ ์ผ๋ก PPR์ ํ์ฑํํ๊ณ ์ถ๋ค๋ฉด
next.config.jsํ์ผ์experimental.ppr: true์ต์ ์ ์ถ๊ฐํ ์ ์์ด์. ํ์ง๋ง 14.1+ ๋ฒ์ ์์๋ ๊ธฐ๋ณธ๊ฐ์ด๋ฏ๋ก ์๋ตํด๋ ๊ด์ฐฎ์์.
1๏ธโฃ Suspense์ fallback ํ์ฉ
PPR์ ํต์ฌ์ React.Suspense ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ์ธ ๋ถ๋ถ์ ๊ฐ์ธ๋ ๊ฒ์ด์์. Suspense๋ ๋น๋๊ธฐ ์์
(๋ฐ์ดํฐ ํ์นญ ๋ฑ)์ด ์๋ฃ๋ ๋๊น์ง fallback UI๋ฅผ ๋ณด์ฌ์ฃผ๊ณ , ์์
์ด ์๋ฃ๋๋ฉด ์ค์ ์ฝํ
์ธ ๋ฅผ ๋ ๋๋งํด์.
import { Suspense } from 'react'; export default function Page() { return ( <main> <h1>๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ ์ ๋ชฉ</h1> <p>์ด๊ฒ์ ๊ฒ์๋ฌผ์ ์ ์ ์ธ ๋ด์ฉ์ด์์.</p> <Suspense fallback={<p>๋๊ธ์ ๋ถ๋ฌ์ค๋ ์ค...</p>}> <CommentsSection /> </Suspense> <Suspense fallback={<p>๊ด๋ จ ๊ฒ์๋ฌผ์ ๋ถ๋ฌ์ค๋ ์ค...</p>}> <RelatedPosts /> </Suspense> </main> ); } async function CommentsSection() { // ์ค์ ๋ก๋ DB๋ API์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋น๋๊ธฐ ํจ์ const comments = await fetchComments(); return ( <section> <h2>๋๊ธ</h2> {comments.map((comment, index) => ( <p key={index}>{comment.text}</p> ))} </section> ); } async function RelatedPosts() { // ์ค์ ๋ก๋ DB๋ API์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋น๋๊ธฐ ํจ์ const related = await fetchRelatedPosts(); return ( <section> <h2>๊ด๋ จ ๊ฒ์๋ฌผ</h2> <ul> {related.map((post, index) => ( <li key={index}>{post.title}</li> ))} </ul> </section> ); } // ๊ฐ์์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ํ์นญ ํจ์ async function fetchComments() { return new Promise(resolve => setTimeout(() => { resolve([{ text: '์ฒซ ๋ฒ์งธ ๋๊ธ์ด์์!' }, { text: '์ ๋ง ์ ์ฉํ ์ ๋ณด๋ค์.' }]); }, 2000)); } async function fetchRelatedPosts() { return new Promise(resolve => setTimeout(() => { resolve([{ title: 'Next.js ์บ์ฑ ์ ๋ต' }, { title: 'React ๋ ๋๋ง ์ต์ ํ' }]); }, 1000)); }
์ ์ฝ๋์์ CommentsSection๊ณผ RelatedPosts ์ปดํฌ๋ํธ๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ํ์นญ์ ์ํํ๊ณ ์์ด์. ์ด ์ปดํฌ๋ํธ๋ค์ Suspense๋ก ๊ฐ์ธ๋ฉด, Next.js๋ ์ด๊ธฐ ์์ฒญ ์ <h1>๊ณผ <p> ํ๊ทธ๋ก ์ด๋ฃจ์ด์ง ์ ์ ์
ธ์ ๋จผ์ ๋ณด๋ด๊ณ , CommentsSection๊ณผ RelatedPosts์ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋๋ฉด ํด๋น ๋ถ๋ถ์ ์คํธ๋ฆฌ๋ฐํ์ฌ ํด๋ผ์ด์ธํธ์ ์ ์กํด์. ์ฌ์ฉ์๋ "๋๊ธ์ ๋ถ๋ฌ์ค๋ ์ค..."์ด๋ผ๋ fallback UI๋ฅผ ๋ณด๋ค๊ฐ ์ค์ ๋๊ธ์ด ๋ํ๋๋ ๊ฒฝํ์ ํ๊ฒ ๋๋ ๊ฑฐ์ฃ .
2๏ธโฃ unstable_noStore() ๋๋ revalidate ์ต์
์ผ๋ก ๋์ ๋ถ๋ถ ๋ช
์
Next.js๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์บ์ํ๋ ค๊ณ ์๋ํด์. PPR์ ์ ๋๋ก ํ์ฉํ๋ ค๋ฉด, ๋์ ์ผ๋ก ๋ ๋๋ง๋์ด์ผ ํ ๋ถ๋ถ์ด ์บ์๋์ง ์๋๋ก ๋ช
์ํด ์ค ํ์๊ฐ ์์ด์.
-
unstable_noStore(): App Router์์ ์๋ฒ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๋ฐ์ดํฐ๋ฅผ ํญ์ ์ต์ ์ํ๋ก ์ ์งํ๊ณ ์ถ์ ๋ ์ฌ์ฉํด์. ์ด ํจ์๊ฐ ํธ์ถ๋๋ ์๊ฐ, ํด๋น ์ปดํฌ๋ํธ์ ๊ทธ ์์ ์ปดํฌ๋ํธ๋ค์ ๋์ ์ผ๋ก ๋ ๋๋ง๋๋๋ก ํ์๋ผ์.import { unstable_noStore } from 'next/cache'; async function DynamicContent() { unstable_noStore(); // ์ด ์ปดํฌ๋ํธ๋ ํญ์ ๋์ ์ผ๋ก ๋ ๋๋ง๋๋๋ก ๋ช ์ const data = await fetch('https://api.example.com/dynamic-data', { cache: 'no-store' }); const json = await data.json(); return <p>๋์ ๋ฐ์ดํฐ: {json.value}</p>; } -
fetch์cache: 'no-store'๋๋revalidate์ต์ :fetchAPI๋ฅผ ์ฌ์ฉํ ๋,cache: 'no-store'์ต์ ์ ์ฃผ๋ฉด ํด๋น ์์ฒญ์ ๊ฒฐ๊ณผ๊ฐ ์บ์๋์ง ์๊ณ ํญ์ ์ต์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋๋ก ํ ์ ์์ด์. ๋ํ,revalidate์ต์ ์ ์ฌ์ฉํ์ฌ ํน์ ์๊ฐ๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ์ฌ๊ฒ์ฆํ๋๋ก ์ค์ ํ ์๋ ์์ด์.async function AlwaysFreshData() { const res = await fetch('https://api.example.com/always-fresh', { cache: 'no-store', // ์ด ๋ฐ์ดํฐ๋ ์ ๋ ์บ์ํ์ง ์๊ณ ํญ์ ์ต์ ์ ๊ฐ์ ธ์์. }); const data = await res.json(); return <p>ํญ์ ์ต์ ๋ฐ์ดํฐ: {data.value}</p>; } async function RevalidatedData() { const res = await fetch('https://api.example.com/revalidated-data', { next: { revalidate: 60 }, // 60์ด๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ์ฌ๊ฒ์ฆํด์. }); const data = await res.json(); return <p>60์ด๋ง๋ค ๊ฐฑ์ ๋๋ ๋ฐ์ดํฐ: {data.value}</p>; }
3๏ธโฃ ์ฝ๋ ์์: ๋ธ๋ก๊ทธ ํฌ์คํธ ์์ธ ํ์ด์ง์ PPR ์ ์ฉ
์ค์ ๋ธ๋ก๊ทธ ํฌ์คํธ ์์ธ ํ์ด์ง์ PPR์ ์ ์ฉํ๋ ์๋๋ฆฌ์ค๋ฅผ ์ดํด๋ณผ๊ฒ์. ๊ฒ์๋ฌผ ๋ด์ฉ์ ์ ์ ์ด์ง๋ง, ๋๊ธ ์น์ ์ ๋์ ์ผ๋ก ์ค์๊ฐ ์ ๋ฐ์ดํธ๋์ด์ผ ํ๋ค๊ณ ๊ฐ์ ํด ๋ด์.
// app/posts/[slug]/page.tsx import { Suspense } from 'react'; import { unstable_noStore } from 'next/cache'; // ๋์ ๋ ๋๋ง์ ๋ช ์ํ๊ธฐ ์ํจ import { ErrorBoundary } from 'react-error-boundary'; // ์๋ฌ ํธ๋ค๋ง์ ์ํด // ๊ฐ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ API ํธ์ถ ํจ์ async function getPostBySlug(slug: string) { // ์ค์ ๋ก๋ DB์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง const posts = { 'first-post': { title: '์ฒซ ๋ฒ์งธ ๊ฒ์๋ฌผ', content: '์ด๊ฒ์ ์ฒซ ๋ฒ์งธ ๊ฒ์๋ฌผ์ ๋ด์ฉ์ ๋๋ค.' }, 'second-post': { title: '๋ ๋ฒ์งธ ๊ฒ์๋ฌผ', content: '๋ ๋ฒ์งธ ๊ฒ์๋ฌผ ๋ด์ฉ๋ ์์ฃผ ์ค์ํด์.' }, }; await new Promise(resolve => setTimeout(resolve, 50)); // ๋คํธ์ํฌ ์ง์ฐ ์๋ฎฌ๋ ์ด์ return posts[slug] || null; } async function getCommentsForPost(postId: string) { unstable_noStore(); // ๋๊ธ์ ํญ์ ์ต์ ์ํ์ฌ์ผ ํ๋ฏ๋ก ๋์ ์ผ๋ก ์ฒ๋ฆฌ // ์ค์ ๋ก๋ API ํธ์ถ ๋๋ DB ์ฟผ๋ฆฌ const comments = { 'first-post': [ { id: 1, author: '๋ธ๋ฃจ', text: '์ ๋ง ์ ์ตํ ๊ธ์ด์์!' }, { id: 2, author: '๋ ์1', text: 'Next.js PPR ์ดํด์ ํฐ ๋์์ด ๋์ด์.' }, ], 'second-post': [ { id: 3, author: '๋ธ๋ฃจ', text: '๋ ๋ฒ์งธ ๊ฒ์๋ฌผ๋ ์ด์ฌํ ์์ฑํ์ด์.' }, ], }; await new Promise(resolve => setTimeout(resolve, 1500)); // ๋๊ธ ๋ก๋ฉ ์ง์ฐ ์๋ฎฌ๋ ์ด์ return comments[postId] || []; } // ๋๊ธ ์น์ ์๋ฒ ์ปดํฌ๋ํธ async function Comments({ postId }: { postId: string }) { const comments = await getCommentsForPost(postId); if (!comments || comments.length === 0) { return <p>์์ง ๋๊ธ์ด ์์ด์. ์ฒซ ๋๊ธ์ ๋จ๊ฒจ์ฃผ์ธ์!</p>; } return ( <section className="mt-8 p-4 bg-gray-50 rounded-lg"> <h2 className="text-2xl font-bold mb-4">๐ฌ ๋๊ธ</h2> {comments.map((comment) => ( <div key={comment.id} className="mb-3 pb-3 border-b border-gray-200 last:border-b-0"> <p className="font-semibold">{comment.author}</p> <p className="text-gray-700">{comment.text}</p> </div> ))} </section> ); } // ์๋ฌ ๋ฐ์ ์ ๋ณด์ฌ์ค UI function CommentsErrorFallback({ error }: { error: Error }) { return ( <div role="alert" className="text-red-600 p-4 border border-red-300 rounded-lg"> <p>โ ๏ธ ๋๊ธ์ ๋ถ๋ฌ์ค๋ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ด์: {error.message}</p> </div> ); } export default async function PostPage({ params }: { params: { slug: string } }) { const post = await getPostBySlug(params.slug); if (!post) { return { notFound: true, }; } return ( <article className="max-w-3xl mx-auto py-8 px-4"> <h1 className="text-4xl font-extrabold mb-4 text-gray-900">{post.title}</h1> <p className="text-lg text-gray-700 leading-relaxed whitespace-pre-wrap">{post.content}</p> {/* ๋๊ธ ์น์ ์ Suspense์ ErrorBoundary ์ ์ฉ */} <ErrorBoundary fallbackRender={({ error }) => <CommentsErrorFallback error={error} />}> <Suspense fallback={ <div className="mt-8 p-4 bg-gray-50 rounded-lg text-gray-600 animate-pulse"> <p>โณ ๋๊ธ์ ๋ถ๋ฌ์ค๋ ์ค์ด์์...</p> </div> }> <Comments postId={params.slug} /> </Suspense> </ErrorBoundary> </article> ); } // generateStaticParams๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋ ์์ ์ ์ ์ ๊ฒฝ๋ก ์์ฑ export async function generateStaticParams() { // ์ค์ ๋ก๋ DB์์ ๋ชจ๋ ํฌ์คํธ์ slug๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง return [ { slug: 'first-post' }, { slug: 'second-post' }, ]; }
์ ์์์์ PostPage๋ generateStaticParams๋ฅผ ํตํด ๋น๋ ์์ ์ ์ ์ ์
ธ๋ก ์์ฑ๋ ์ ์์ด์. ๊ฒ์๋ฌผ์ ์ ๋ชฉ๊ณผ ๋ด์ฉ์ ์ ์ ์
ธ์ ํฌํจ๋์ด ๋น ๋ฅด๊ฒ ๋ก๋ฉ๋์ฃ . ๋ฐ๋ฉด Comments ์ปดํฌ๋ํธ๋ unstable_noStore()๋ฅผ ์ฌ์ฉํ๊ณ Suspense๋ก ๊ฐ์ธ์ ธ ์๊ธฐ ๋๋ฌธ์, ์ด๊ธฐ์๋ fallback UI๊ฐ ๋ณด์ด๋ค๊ฐ ๋๊ธ ๋ฐ์ดํฐ๊ฐ ๋ก๋ฉ๋๋ฉด ๋์ ์ผ๋ก ์คํธ๋ฆฌ๋ฐ๋์ด ํ์ด์ง์ ๋ํ๋์. ErrorBoundary๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ธ ๋ก๋ฉ ์ค ๋ฐ์ํ ์ ์๋ ์๋ฌ๋ gracefullyํ๊ฒ ์ฒ๋ฆฌํ๊ณ ์์ด์.
๐ก PPR ์ต์ ํ ํ๊ณผ ๊ณ ๋ ค์ฌํญ
0๏ธโฃ Suspense ๊ฒฝ๊ณ์ ์ค์์ฑ
Suspense ๊ฒฝ๊ณ๋ PPR์ ์ฑ๋ฅ์ ๋งค์ฐ ์ค์ํ ์ํฅ์ ๋ฏธ์ณ์. ๋๋ฌด ํฐ ๋จ์๋ฅผ Suspense๋ก ๊ฐ์ธ๋ฉด ๋์ ์ฝํ
์ธ ์ ์์ด ๋ง์์ ธ ์ด๊ธฐ ๋ก๋ฉ ์๋ ์ด์ ์ ์์ ์ ์๊ณ , ๋๋ฌด ์์ ๋จ์๋ฅผ ๊ฐ์ธ๋ฉด ๋ณต์ก๋๊ฐ ์ฆ๊ฐํ ์ ์์ด์. ์ฌ์ฉ์์๊ฒ ์๋ฏธ ์๋ ์ต์ ๋จ์๋ก Suspense๋ฅผ ์ ์ฉํ๋ ๊ฒ์ด ์ค์ํด์.
์๋ฅผ ๋ค์ด, ํ์ด์ง ์ ์ฒด๋ฅผ Suspense๋ก ๊ฐ์ธ๊ธฐ๋ณด๋ค๋, ๋
๋ฆฝ์ ์ผ๋ก ๋ก๋ฉ๋ ์ ์๋ ์์ ฏ์ด๋ ์น์
๋จ์๋ก ๋๋์ด ์ ์ฉํ๋ ๊ฒ์ด ์ข์์.
1๏ธโฃ ๋ฐ์ดํฐ ํ์นญ ์ ๋ต (React cache, fetch ํ์ฅ)
Next.js 13+ App Router์์๋ ์๋ฒ ์ปดํฌ๋ํธ์์ fetch๋ฅผ ์ฌ์ฉํ ๋ ์๋์ผ๋ก ์์ฒญ์ ์บ์ํ๊ณ ์ค๋ณต์ ์ ๊ฑฐํด ์ค์. ํ์ง๋ง PPR ํ๊ฒฝ์์๋ ํน์ ๋ฐ์ดํฐ๊ฐ ํญ์ ์ต์ ์ด์ด์ผ ํ๋์ง, ์๋๋ฉด ์บ์๋์ด๋ ๋๋์ง ๋ช
ํํ ๊ตฌ๋ถํ๋ ๊ฒ์ด ์ค์ํด์.
- ์บ์๊ฐ ํ์ํ ๊ฒฝ์ฐ:
fetch์ ๊ธฐ๋ณธ ๋์์ ์ฌ์ฉํ๊ฑฐ๋,revalidate์ต์ ์ ํตํด ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ํด์. - ์บ์๊ฐ ํ์ ์๋ ๊ฒฝ์ฐ:
fetch์cache: 'no-store'์ต์ ์ ๋ช ์ํ๊ฑฐ๋,unstable_noStore()๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ์ปดํฌ๋ํธ๊ฐ ๋์ ์ผ๋ก ๋ ๋๋ง๋๋๋ก ํด์.
2๏ธโฃ ์๋ฌ ํธ๋ค๋ง (ErrorBoundary)
PPR ํ๊ฒฝ์์๋ ๋์ ์ธ ๋ถ๋ถ์ด ๋น๋๊ธฐ์ ์ผ๋ก ๋ก๋ฉ๋๊ธฐ ๋๋ฌธ์, ํด๋น ๋ถ๋ถ์์ ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ์ ์ฒด ํ์ด์ง๊ฐ ๋ง๊ฐ์ง๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ErrorBoundary๋ฅผ ์ ์ ํ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํด์. Suspense์ ๋ง์ฐฌ๊ฐ์ง๋ก, ์๋ฌ ๋ฐ์ ์ ์ฌ์ฉ์์๊ฒ ์๋ฏธ ์๋ fallback UI๋ฅผ ์ ๊ณตํด์ผ ํด์.
3๏ธโฃ SEO์ ์ ๊ทผ์ฑ
PPR์ ์ด๊ธฐ HTML์ ์ ์ ์ฝํ
์ธ ๊ฐ ํฌํจ๋๋ฏ๋ก SEO์ ๋งค์ฐ ์ ๋ฆฌํด์. ๊ฒ์ ์์ง ํฌ๋กค๋ฌ๋ ์ ์ ์
ธ์ ํตํด ํ์ด์ง์ ํต์ฌ ๋ด์ฉ์ ๋น ๋ฅด๊ฒ ์ธ๋ฑ์ฑํ ์ ์์ด์. ๋์ ์ผ๋ก ๋ก๋ฉ๋๋ ์ฝํ
์ธ ๋ ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์ ์ก๋๋ฏ๋ก, ํฌ๋กค๋ฌ๊ฐ ์ถฉ๋ถํ ๊ธฐ๋ค๋ฆฌ๋ฉด ๋ด์ฉ์ ํ์ฑํ ์ ์๋ต๋๋ค.
ํ์ง๋ง fallback UI๊ฐ ๋๋ฌด ์ค๋ ๋
ธ์ถ๋๊ฑฐ๋, ์ค์ํ ์ฝํ
์ธ ๊ฐ Suspense ๋ค์ ์จ๊ฒจ์ ธ ์์ด ์ด๊ธฐ ๋ก๋ฉ์ด ์ง์ฐ๋๋ฉด ์ฌ์ฉ์ ๊ฒฝํ์ ๋ถ์ ์ ์ธ ์ํฅ์ ์ค ์ ์์ผ๋ ์ฃผ์ํด์ผ ํด์.
๐ ์ ๋ฆฌํ๋ฉฐ
0๏ธโฃ PPR์ ๊ฐ๋ ฅํ ์ด์ ์์ฝ
์ค๋ ์ฐ๋ฆฌ๋ Next.js์ ํ์ ์ ์ธ ๊ธฐ๋ฅ์ธ Partial Prerendering (PPR)์ ๋ํด ์์ธํ ์ดํด๋ณด์์ด์. PPR์ ๋ค์๊ณผ ๊ฐ์ ๊ฐ๋ ฅํ ์ด์ ์ ์ ๊ณตํด์.
- ์ด๊ณ ์ ์ด๊ธฐ ๋ก๋ฉ: ์ ์ ์
ธ์ ํตํด ์ฌ์ฉ์์๊ฒ ์ฆ๊ฐ์ ์ธ ํ์ด์ง ๋ก๋ฉ ๊ฒฝํ์ ์ ์ฌํด์.
- ์ค์๊ฐ ๋์ ์ฝํ
์ธ :
Suspense์ ์คํธ๋ฆฌ๋ฐ์ ํตํด ๋์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ต์ ์ํ๋ก ์ ์งํ๋ฉด์๋ ๋ถ๋๋ฝ๊ฒ ํตํฉํด์. - ์ต์ ์ ์ฌ์ฉ์ ๊ฒฝํ: ๋น ๋ฅธ ์ด๊ธฐ ๋ก๋ฉ๊ณผ ์ต์ ๋ฐ์ดํฐ ์ ๊ณต์ผ๋ก ์ฌ์ฉ์ ๋ง์กฑ๋๋ฅผ ๋์ฌ์.
- ๊ฐ๋ ฅํ SEO: ๊ฒ์ ์์ง ํฌ๋กค๋ฌ๊ฐ ํต์ฌ ์ฝํ
์ธ ๋ฅผ ์ฝ๊ฒ ์ธ๋ฑ์ฑํ ์ ์๋๋ก ๋์์ค์.
- ๊ฐ๋ฐ ํธ์์ฑ: SSR, SSG, ISR์ ์ฅ์ ์ ํ ๋ฒ์ ๋๋ฆฌ๋ฉด์๋ ๋ณต์กํ ์บ์ฑ ์ ๋ต์ ๋จ์ํํ ์ ์์ด์.
1๏ธโฃ ๋ค์ ๋จ๊ณ: ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์ ์ ์ฉํด ๋ณด์ธ์
PPR์ Next.js App Router๋ฅผ ์ฌ์ฉํ๋ ํ๋ก์ ํธ์ ์น ์ฑ๋ฅ๊ณผ ์ฌ์ฉ์ ๊ฒฝํ์ ํ ๋จ๊ณ ๋์ด์ฌ๋ฆด ์ ์๋ ๋งค์ฐ ํจ๊ณผ์ ์ธ ๋๊ตฌ์์. ํนํ ๋ธ๋ก๊ทธ, ์ด์ปค๋จธ์ค ์์ธ ํ์ด์ง, ๋์๋ณด๋ ๋ฑ ์ ์ ์ธ ๋ ์ด์์ ์์ ๋์ ์ธ ๋ฐ์ดํฐ๊ฐ ํ์ํ ํ์ด์ง์ ๊ฐ๋ ฅํ๊ฒ ์ถ์ฒํด์.
์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์ฌ๋ฌ๋ถ์ Next.js ํ๋ก์ ํธ์ Partial Prerendering์ ์ ์ฉํด ๋ณด์๊ณ , ๋์ฑ ๋น ๋ฅด๊ณ ๋ฐ์์ฑ ์ข์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง๋ค์ด๋ณด์๊ธธ ๋ฐ๋ผ์! ๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ์ธ์ ๋ ์ง ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์ธ์. ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ๋ ํญ์ ํจ๊ป ์ฑ์ฅํ๋ ๊ณณ์ด๋๊น์.
๐ฎ ์ฐธ๊ณ
- Next.js Docs: Partial Prerendering
- Next.js Blog: Partial Prerendering in Next.js 14.1
- React Docs: Suspense
- React Docs: Error Boundaries
์ฐ๊ด๋ ํฌ์คํธ
- ๋จ์ด: 1,786๊ฐ19๋ถ
[๐ค] TypeScript ์กฐ๊ฑด๋ถ ํ์ ๊ณผ infer ํค์๋: ๋ณต์กํ ํ์ ๋ ์์ฝ๊ฒ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ
TypeScript ๊ฐ๋ฐ์์ ๋ง์ฃผํ๋ ๋ณต์กํ ํ์ ์ถ๋ก ๋ฌธ์ , ์กฐ๊ฑด๋ถ ํ์ ๊ณผ infer ํค์๋๋ฅผ ํ์ฉํ๋ฉด ํจ์ฌ ์ฐ์ํ๊ณ ๊ฐ๋ ฅํ๊ฒ ํด๊ฒฐํ ์ ์์ด์. ์ค์ ์์ ์ ํจ๊ป ๊ทธ ํ์ฉ๋ฒ์ ์ฌ๋ ์๊ฒ ๋ค๋ค๋ด ๋๋ค.
- ๋จ์ด: 1,697๊ฐ21๋ถ
[๐ค] JavaScript ์ด๋ฒคํธ ๋ฃจํ(Event Loop) ์์ ์ ๋ณต: ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ฐํ์ ๋์ ์๋ฆฌ
JavaScript์ ํต์ฌ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ธ ์ด๋ฒคํธ ๋ฃจํ์ ๋์ ์๋ฆฌ๋ฅผ ์ฌ๋ ์๊ฒ ํํค์ณ ๋ด์. ์ฝ ์คํ, ํ์คํฌ ํ, ๋ง์ดํฌ๋กํ์คํฌ ํ์์ ์ํธ์์ฉ์ ์ดํดํ๊ณ , ์ค๋ฌด์์ ๋ง์ฃผ์น๋ ๋น๋๊ธฐ ์ฝ๋์ ๋์์ ๋ช ํํ ์์ธกํ๋ ๋ฐฉ๋ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,960๊ฐ23๋ถ
[๐ค] Next.js Server & Client Components, ์ค์ ์์ ํ๋ช ํ๊ฒ ์ ํํ๋ ๊ฐ์ด๋
Next.js App Router์์ Server Components์ Client Components ์ค ์ด๋ค ๊ฒ์ ์ฌ์ฉํด์ผ ํ ์ง ๊ณ ๋ฏผ์ด์ ๊ฐ์? ์ด ๊ธ์์ ๋ ์ปดํฌ๋ํธ์ ํต์ฌ ์ฐจ์ด์ , ์ฌ์ฉ ์์ , ๊ทธ๋ฆฌ๊ณ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ์ค์ ์ ๋ต์ ๋ธ๋ฃจ๊ฐ ์๋ ค๋๋ฆด๊ฒ์.
- ๋จ์ด: 1,878๊ฐ21๋ถ
[๐ค] TypeScript satisfies ์ฐ์ฐ์: ํ์ ์ถ๋ก ๊ณผ ์์ ์ฑ์ ๋์์ ์ก๋ ๋น๋ฒ
TypeScript์ `satisfies` ์ฐ์ฐ์๋ฅผ ํ์ฉํ์ฌ ํ์ ์ถ๋ก ์ ์ ์ฐ์ฑ์ ์ ์งํ๋ฉด์๋ ์๊ฒฉํ ํ์ ์์ ์ฑ์ ํ๋ณดํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. ์ค์ฉ์ ์ธ ์์๋ฅผ ํตํด ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํฉ๋๋ค.
- ๋จ์ด: 1,207๊ฐ15๋ถ
[๐ค] React 19 ์๋ก์ด ๊ธฐ๋ฅ: use ํ , Actions, ๊ทธ๋ฆฌ๊ณ ์ปดํ์ผ๋ฌ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
React 19์ ํต์ฌ ๋ณ๊ฒฝ ์ฌํญ์ธ use ํ , ์๋ฒ ์ก์ , ๊ทธ๋ฆฌ๊ณ React ์ปดํ์ผ๋ฌ์ ๋์ ๋ฐฐ๊ฒฝ๊ณผ ์ค์ ํ์ฉ ์์๋ฅผ ์ด์ค๊ธ ๊ฐ๋ฐ์ ๋๋์ด์ ๋ง์ถฐ ์์ธํ ์ค๋ช ํฉ๋๋ค. ์ต์ React ์ ๋ฐ์ดํธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ๊ณผ ๊ฐ๋ฐ ๊ฒฝํ์ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
- ๋จ์ด: 1,512๊ฐ16๋ถ
[๐ค] Next.js App Router ์บ์ฑ ์ ๋ต: ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ (revalidatePath, revalidateTag) ์๋ฒฝ ๊ฐ์ด๋
Next.js 14 App Router์์ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์บ์ฑ ์ ๋ต๊ณผ revalidatePath, revalidateTag๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์์๋ณด๊ณ ์น ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.