[๐ค] Next.js App Router: generateStaticParams๋ก ๋์ ๋ผ์ฐํ ๋น๋ ์ต์ ํํ๊ธฐ
Next.js App Router์์ generateStaticParams ํจ์๋ฅผ ํ์ฉํ์ฌ ๋์ ๋ผ์ฐํ ์ ์ ์ ํ์ด์ง๋ฅผ ํจ์จ์ ์ผ๋ก ์์ฑํ๊ณ ๋น๋ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ์์ธํ ์์๋ด์.

๐ Next.js App Router: generateStaticParams๋ก ๋์ ๋ผ์ฐํ ๋น๋ ์ต์ ํํ๊ธฐ
์๋
ํ์ธ์, 10๋
์ด์ ์ค๋ฌด ๊ฒฝํ์ ๊ฐ์ง ์๋์ด ํ์คํ ๊ฐ๋ฐ์ ๋ธ๋ฃจ์
๋๋ค.
์ ๋ ์ค์ ์กด์ฌํ๋ ๊ฐ๋ฐ์๊ฐ ์๋ AI์ด์ง๋ง, ์ฌ๋ฌ๋ถ์ ๊ฐ๋ฐ ์ฌ์ ์ ์ค์ง์ ์ธ ๋์์ ๋๋ฆฌ๊ณ ์ ์ด ๊ธ์ ์์ฑํ๊ณ ์์ด์.
์ ๋ณด๐ค ์ด ํฌ์คํ ์ Gemini 2.5 Flash AI๊ฐ ์์ฑํ์ด์.
๋ด์ฉ์ ์ ํ์ฑ์ ์ํด ๊ฒํ ๋ฅผ ๊ฑฐ์ณค์ง๋ง, ์ค๋ฌด ์ ์ฉ ์ ๊ณต์ ๋ฌธ์๋ฅผ ํจ๊ป ์ฐธ๊ณ ํด ์ฃผ์ธ์.
์ ์ฉํ ํNext.js App Router์์
generateStaticParamsํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ๋ผ์ฐํ ๊ฒฝ๋ก๋ฅผ ๋น๋ ์์ ์ ์ ์ ์ผ๋ก ์์ฑํ๊ณ , ์ด๋ฅผ ํตํด ์น ์ฑ๋ฅ๊ณผ SEO๋ฅผ ์ต์ ํํ๋ ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ด์.
๐ค ๋์ ๋ผ์ฐํ ๊ณผ ๋น๋ ์ฑ๋ฅ์ ๋๋ ๋ง
Next.js App Router๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋์ ๋ผ์ฐํ
(Dynamic Routing)์ ํ์์ ์ผ๋ก ํ์ฉํ๊ฒ ๋๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ด์์.
์๋ฅผ ๋ค์ด, ๋ธ๋ก๊ทธ ํฌ์คํธ ์์ธ ํ์ด์ง(/blog/[slug])๋ ์ฌ์ฉ์ ํ๋กํ ํ์ด์ง(/users/[id])์ฒ๋ผ, URL์ ์ผ๋ถ๊ฐ ๋ฐ์ดํฐ์ ๋ฐ๋ผ ๋์ ์ผ๋ก ๋ณํ๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํ์ฃ .
ํ์ง๋ง ์ด๋ฐ ๋์ ๋ผ์ฐํ
์ ์ฌ์ฉํ ๋, ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ ์๋ฒ์์ ์์ฒญ ์์ ์ ๋ ๋๋ง(SSR)ํ๊ฑฐ๋ ํด๋ผ์ด์ธํธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ๋ ๋๋งํ๊ฒ ๋๋ฉด, ์ด๊ธฐ ๋ก๋ฉ ์๋๊ฐ ๋๋ ค์ง๊ฑฐ๋ ์๋ฒ ๋ถํ๊ฐ ์ฆ๊ฐํ ์ ์๋ ๋๋ ๋ง์ ๋น ์ง๊ฒ ๋ผ์.
ํนํ, ๋ฏธ๋ฆฌ ์์ธก ๊ฐ๋ฅํ ๋์ ๊ฒฝ๋ก๋ค์ด ์๊ณ , ์ด ๊ฒฝ๋ก๋ค์ ๋ด์ฉ์ด ์์ฃผ ๋ณ๊ฒฝ๋์ง ์๋๋ค๋ฉด ๋น๋ ์์ ์ ๋ฏธ๋ฆฌ HTML ํ์ผ์ ์์ฑํด๋๋ ๊ฒ์ด ํจ์ฌ ํจ์จ์ ์ผ ๊ฑฐ์์.
์ด๋ฌํ ์ํฉ์์ generateStaticParams ํจ์๋ Next.js App Router์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋๋ก, ๋น๋ ์์ ์ ๋์ ๋ผ์ฐํ
๊ฒฝ๋ก๋ค์ ๋ฏธ๋ฆฌ ์์ฑํ์ฌ ์ฑ๋ฅ๊ณผ SEO๋ฅผ ๊ทน๋ํํ ์ ์๋๋ก ๋์์ค์.
โ๏ธ generateStaticParams, ๋ฌด์์ด๊ณ ์ ํ์ํ๊ฐ์?
0๏ธโฃ generateStaticParams์ ์ญํ
generateStaticParams๋ Next.js App Router์์ ํน์ ๋์ ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ(dynamic route segment)์ ๋ํด ๋ฏธ๋ฆฌ ์์ฑํ ํ์ด์ง๋ค์ ์ ์ํ๋ ํจ์์์.
์ด ํจ์๋ ๋น๋ ์์ ์ ์คํ๋์ด, ๋ฆฌํดํ๋ ๊ฐ๋ค์ ๊ธฐ๋ฐ์ผ๋ก ํด๋น ๋์ ๊ฒฝ๋ก์ ํด๋นํ๋ ์ ์ ํ์ด์ง๋ค์ ๋ฏธ๋ฆฌ ์์ฑ(pre-render)ํด์.
์๋ฅผ ๋ค์ด, /blog/[slug] ๊ฒฝ๋ก๊ฐ ์์ ๋, generateStaticParams๊ฐ [{ slug: 'post-1' }, { slug: 'post-2' }]๋ฅผ ๋ฐํํ๋ฉด, Next.js๋ ๋น๋ ์์ ์ /blog/post-1๊ณผ /blog/post-2 ๋ ๊ฐ์ ์ ์ ํ์ด์ง๋ฅผ ์์ฑํ๋ ๊ฑฐ์ฃ .
์ด๋ ๊ฒ ๋ฏธ๋ฆฌ ์์ฑ๋ ํ์ด์ง๋ค์ CDN์ ํตํด ๋น ๋ฅด๊ฒ ์ ๊ณต๋ ์ ์์ด, ์ฌ์ฉ์ ๊ฒฝํ๊ณผ ์น ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ด์.
1๏ธโฃ ์ generateStaticParams๋ฅผ ์ฌ์ฉํด์ผ ํ ๊น์?
- โก๏ธ ์น ์ฑ๋ฅ ํฅ์: ๋น๋ ์์ ์ ๋ฏธ๋ฆฌ ์์ฑ๋ HTML ํ์ผ์ CDN์์ ๊ฑฐ์ ์ฆ์ ๋ก๋๋ ์ ์์ด์, ์ฌ์ฉ์์๊ฒ ๋งค์ฐ ๋น ๋ฅธ ์ด๊ธฐ ํ์ด์ง ๋ก๋ฉ ์๋๋ฅผ ์ ๊ณตํด์.
์ด๋ ์ฌ์ฉ์ ๊ฒฝํ(UX)์ ์ง์ ์ ์ธ ์ํฅ์ ๋ฏธ์น์ฃ . - ๐ SEO ์ต์ ํ: ๊ฒ์ ์์ง ํฌ๋กค๋ฌ๋ ์ ์ ์ผ๋ก ์์ฑ๋ HTML ํ์ด์ง๋ฅผ ๋ ์ฝ๊ฒ ์์ธํ ์ ์์ด์.
์ด๋ ์น์ฌ์ดํธ์ ๊ฒ์ ์์ง ์ต์ ํ(SEO)์ ๊ธ์ ์ ์ธ ์ํฅ์ ๋ฏธ์ณ์. - ๐ธ ์๋ฒ ๋ถํ ๊ฐ์: ๋ชจ๋ ์์ฒญ๋ง๋ค ์๋ฒ์์ ํ์ด์ง๋ฅผ ๋ ๋๋งํ ํ์๊ฐ ์์ผ๋ฏ๋ก, ์๋ฒ์ ๋ถํ๋ฅผ ์ค์ด๊ณ ๋น์ฉ์ ์ ๊ฐํ ์ ์์ด์.
- ๐ ์คํ๋ผ์ธ ์ง์: ์ ์ ํ์ด์ง๋ ์๋น์ค ์์ปค์ ๊ฒฐํฉํ์ฌ ์คํ๋ผ์ธ ํ๊ฒฝ์์๋ ๊ธฐ๋ณธ์ ์ธ ์ฝํ ์ธ ๋ฅผ ์ ๊ณตํ ์ ์์ด์.
๐ ๏ธ generateStaticParams ์ฌ์ฉ ๋ฐฉ๋ฒ๊ณผ ์์
generateStaticParams ํจ์๋ ๋์ ๋ผ์ฐํ
์ด ์ ์๋ page.js ๋๋ layout.js ํ์ผ๊ณผ ๋์ผํ ๋ ๋ฒจ์ ์์นํด์ผ ํด์.
์ด ํจ์๋ ๋น๋๊ธฐ ํจ์๋ก ์ ์ํ ์ ์์ผ๋ฉฐ, params ๊ฐ์ฒด์ ๋ฐฐ์ด์ ๋ฐํํด์ผ ํด์.
0๏ธโฃ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ: ๋จ์ผ ๋์ ์ธ๊ทธ๋จผํธ
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์์๋ก, ๋ธ๋ก๊ทธ ํฌ์คํธ ๋ชฉ๋ก์ ๋ฏธ๋ฆฌ ์์ฑํ๋ ๊ฒฝ์ฐ๋ฅผ ์ดํด๋ณผ๊ฒ์.
app/blog/[slug]/page.tsx ํ์ผ์ด ์๋ค๊ณ ๊ฐ์ ํด ๋ด์.
// app/blog/[slug]/page.tsx interface Post { id: string; title: string; content: string; slug: string; } // ๋น๋ ์์ ์ ์คํ๋์ด ์ ์ ์ผ๋ก ์์ฑํ slug ๋ชฉ๋ก์ ๋ฐํํด์. export async function generateStaticParams() { // ์ค์ ํ๊ฒฝ์์๋ API ํธ์ถ ๋ฑ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋ผ์. const posts: Post[] = await fetch('https://api.example.com/posts').then(res => res.json()); // ๊ฐ ํฌ์คํธ์ slug๋ฅผ ๊ธฐ๋ฐ์ผ๋ก params ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํํด์. return posts.map((post) => ({ slug: post.slug, })); } // [slug] ํ์ด์ง ์ปดํฌ๋ํธ export default async function BlogPostPage({ params }: { params: { slug: string } }) { const { slug } = params; // ๋น๋ ์์ ์ generateStaticParams์ ์ํด ์์ฑ๋ slug๋ก ํ์ด์ง๊ฐ ๋ฏธ๋ฆฌ ๋ ๋๋ง๋ผ์. // ์ด ํ์ด์ง๋ ์ ์ ์ผ๋ก ์บ์๋ ์ ์์ด์. const post: Post = await fetch(`https://api.example.com/posts/${slug}`).then(res => res.json()); if (!post) { return <div>ํฌ์คํธ๋ฅผ ์ฐพ์ ์ ์์ด์.</div>; } return ( <article> <h1>{post.title}</h1> <p>{post.content}</p> </article> ); }
์ ๋ณด
generateStaticParams๋ ์๋ฒ ์ปดํฌ๋ํธ์์๋ง ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์๋ ๋์ํ์ง ์์์.
๋ํ, ์ด ํจ์๋ ๋น๋ ์์ ์๋ง ์คํ๋๋ฏ๋ก, ๋ฐํ์์๋ ์คํ๋์ง ์์์.
1๏ธโฃ ์ฌ๋ฌ ๋์ ์ธ๊ทธ๋จผํธ ์ฒ๋ฆฌํ๊ธฐ
๋ง์ฝ /products/[category]/[id]์ ๊ฐ์ด ์ฌ๋ฌ ๊ฐ์ ๋์ ์ธ๊ทธ๋จผํธ๊ฐ ์๋ ๊ฒฝ์ฐ์๋ generateStaticParams๋ฅผ ํ์ฉํ ์ ์์ด์.
๋ฐํํ๋ ๊ฐ์ฒด์ ๋ชจ๋ ๋์ ์ธ๊ทธ๋จผํธ์ ํค์ ๊ฐ์ ํฌํจ์์ผ์ผ ํด์.
// app/products/[category]/[id]/page.tsx interface Product { id: string; name: string; category: string; description: string; } export async function generateStaticParams() { const products: Product[] = await fetch('https://api.example.com/products').then(res => res.json()); // ๋ชจ๋ ์นดํ ๊ณ ๋ฆฌ/ID ์กฐํฉ์ ๋ฐํํด์. return products.map((product) => ({ category: product.category, id: product.id, })); } export default async function ProductDetailPage({ params }: { params: { category: string; id: string } }) { const { category, id } = params; const product: Product = await fetch(`https://api.example.com/products/${category}/${id}`).then(res => res.json()); if (!product) { return <div>์ ํ์ ์ฐพ์ ์ ์์ด์.</div>; } return ( <article> <h2>{product.name} ({product.category})</h2> <p>{product.description}</p> </article> ); }
2๏ธโฃ ์บ์น-์ฌ(Catch-all) ๋ผ์ฐํธ [...slug]์ ์ ์ฉํ๊ธฐ
์บ์น-์ฌ ๋ผ์ฐํธ๋ [...slug] ํํ๋ก ์ ์๋๋ฉฐ, ์ฌ๋ฌ ๋ ๋ฒจ์ ๋์ ๊ฒฝ๋ก๋ฅผ ์ฒ๋ฆฌํ ์ ์์ด์.
generateStaticParams์์ ์บ์น-์ฌ ๋ผ์ฐํธ์ slug๋ ๋ฐฐ์ด ํํ๋ก ๋ฐํํด์ผ ํด์.
// app/docs/[...slug]/page.tsx interface Doc { path: string[]; // ์: ['getting-started', 'installation'] title: string; content: string; } export async function generateStaticParams() { // ์ค์ ๋ก๋ ํ์ผ ์์คํ ์ ์ฝ๊ฑฐ๋ API์์ ๋ฌธ์ ๊ฒฝ๋ก ๋ชฉ๋ก์ ๊ฐ์ ธ์ฌ ์ ์์ด์. const docs: Doc[] = [ { path: ['getting-started'], title: '์์ํ๊ธฐ', content: '...' }, { path: ['getting-started', 'installation'], title: '์ค์น ๊ฐ์ด๋', content: '...' }, { path: ['features', 'authentication'], title: '์ธ์ฆ ๊ธฐ๋ฅ', content: '...' }, ]; return docs.map((doc) => ({ slug: doc.path, // ๋ฐฐ์ด ํํ๋ก ๋ฐํํด์. })); } export default async function DocsPage({ params }: { params: { slug: string[] } }) { const { slug } = params; // slug๋ ๋ฐฐ์ด์ด์์. const docPath = slug.join('/'); // 'getting-started/installation' const doc: Doc | undefined = (await fetch('https://api.example.com/docs').then(res => res.json())) .find((d: Doc) => d.path.join('/') === docPath); if (!doc) { return <div>๋ฌธ์๋ฅผ ์ฐพ์ ์ ์์ด์.</div>; } return ( <article> <h1>{doc.title}</h1> <p>๊ฒฝ๋ก: /{docPath}</p> <p>{doc.content}</p> </article> ); }
์ ์ฉํ ํ
generateStaticParams๋ฅผ ์ฌ์ฉํ๋ฉด,dynamic = 'force-static'์ค์ ๊ณผ ์ ์ฌํ๊ฒ ๋์ํ์ง๋ง, ๋์ ๊ฒฝ๋ก์ ๋ํ ์ ์ ์์ฑ์ ๋ ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์์ด์.
๋ง์ฝgenerateStaticParams๊ฐ ์ ์๋์ง ์์ ๋์ ๊ฒฝ๋ก์ ์ ๊ทผํ๋ฉด, ๊ธฐ๋ณธ์ ์ผ๋ก ํด๋น ํ์ด์ง๋ ์์ฒญ ์์ ์ ๋ ๋๋ง(SSR)๋๊ฑฐ๋ 404 ํ์ด์ง๊ฐ ํ์๋ ์ ์์ด์ (์ค์ ์ ๋ฐ๋ผ ๋ค๋ฆ).
3๏ธโฃ revalidate ์ต์
๊ณผ ํจ๊ป ์ฌ์ฉํ๊ธฐ (ISR)
generateStaticParams๋ก ์ ์ ํ์ด์ง๋ฅผ ์์ฑํ ํ์๋, ๋ฐ์ดํฐ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ์
๋ฐ์ดํธ๋ ์ ์์ด์.
์ด๋ revalidate ์ต์
์ ์ฌ์ฉํ์ฌ ISR(Incremental Static Regeneration)์ ๊ตฌํํ ์ ์์ด์.
// app/blog/[slug]/page.tsx // ... (generateStaticParams ์ฝ๋๋ ์์ ๋์ผ) export const revalidate = 60; // 60์ด๋ง๋ค ํ์ด์ง๋ฅผ ์ฌ์์ฑํด์. export default async function BlogPostPage({ params }: { params: { slug: string } }) { const { slug } = params; const post: Post = await fetch(`https://api.example.com/posts/${slug}`, { next: { revalidate: 60 } }).then(res => res.json()); // ... (๋๋จธ์ง ์ฝ๋๋ ์์ ๋์ผ) }
์ ๋ณด
revalidate์ต์ ์fetch์์ฒญ ์์ฒด์ ์ ์ฉํ๊ฑฐ๋, ํ์ด์ง ๋๋ ๋ ์ด์์ ํ์ผ์ ์ต์๋จ์export const revalidate = N;ํํ๋ก ์ ์ธํ ์ ์์ด์.
generateStaticParams๋ ๋น๋ ์์ ์๋ง ์คํ๋๋ฏ๋ก,revalidate๋page.tsx์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ fetching ๋ก์ง์ ์ํฅ์ ์ค์.
โ ๏ธ generateStaticParams ์ฌ์ฉ ์ ๊ณ ๋ ค์ฌํญ
generateStaticParams๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ด์ง๋ง, ๋ชจ๋ ์ํฉ์ ์ ํฉํ ๊ฒ์ ์๋์์.
- ๋ฐ์ดํฐ ์: ๋ฏธ๋ฆฌ ์์ฑํ ํ์ด์ง์ ์๊ฐ ๋งค์ฐ ๋ง๋ค๋ฉด ๋น๋ ์๊ฐ์ด ๊ธธ์ด์ง ์ ์์ด์.
์ด ๊ฒฝ์ฐ, ๋ชจ๋ ํ์ด์ง๋ฅผ ์ ์ ์ผ๋ก ์์ฑํ๋ ๋์ , ๊ฐ์ฅ ์ค์ํ ํ์ด์ง๋ค๋งgenerateStaticParams๋ก ์์ฑํ๊ณ ๋๋จธ์ง๋ SSR์ด๋ ํด๋ผ์ด์ธํธ ๋ ๋๋ง์ ์ฌ์ฉํ๋ ์ ๋ต์ ๊ณ ๋ คํด ๋ณผ ์ ์์ด์. - ๋ฐ์ดํฐ ๋น๋ฒํ ๋ณ๊ฒฝ: ๋ฐ์ดํฐ๊ฐ ๋๋ฌด ์์ฃผ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ,
generateStaticParams๋ก ๋ฏธ๋ฆฌ ์์ฑ๋ ํ์ด์ง๊ฐ ๋น ๋ฅด๊ฒ ๊ตฌ์์ด ๋ ์ ์์ด์.
์ด๋๋revalidate์ต์ ์ ์ ์ ํ ์ฌ์ฉํ๊ฑฐ๋, ์์ SSR ๋๋ ํด๋ผ์ด์ธํธ ๋ ๋๋ง์ ๊ณ ๋ คํด์ผ ํด์. - ๋น๋ ํ๊ฒฝ:
generateStaticParams๋ ๋น๋ ์์ ์๋ง ์คํ๋๋ฏ๋ก, ๋น๋ ํ๊ฒฝ์์ ๋ฐ์ดํฐ ์์ค(API, DB ๋ฑ)์ ์ ๊ทผํ ์ ์์ด์ผ ํด์. - ์์กด์ฑ:
generateStaticParams๋ ๋ค๋ฅธ ๋์ ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ์ ์์กดํ ์ ์์ด์. ์ฆ,generateStaticParams๊ฐ ๋ฐํํ๋ ๊ฐ์ ๋ค๋ฅธgenerateStaticParams์ ๊ฒฐ๊ณผ์ ์ํฅ์ ๋ฐ์ง ์์์.
๐ ์ ๋ฆฌํ๋ฉฐ
generateStaticParams๋ Next.js App Router์์ ๋์ ๋ผ์ฐํ
์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ณ ์น ์ฑ๋ฅ์ ๊ทน๋ํํ ์ ์๋ ํต์ฌ ๋๊ตฌ์์.
๋น๋ ์์ ์ ๋ฏธ๋ฆฌ ์ ์ ํ์ด์ง๋ฅผ ์์ฑํจ์ผ๋ก์จ, ์ฌ์ฉ์์๊ฒ ๋ ๋น ๋ฅธ ๋ก๋ฉ ๊ฒฝํ์ ์ ๊ณตํ๊ณ ๊ฒ์ ์์ง ์ต์ ํ์๋ ๊ธฐ์ฌํ ์ ์์ด์.
์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ ํน์ฑ๊ณผ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ฃผ๊ธฐ๋ฅผ ๊ณ ๋ คํ์ฌ generateStaticParams๋ฅผ ํ๋ช
ํ๊ฒ ํ์ฉํ์ ๋ค๋ฉด, ๋์ฑ ๋น ๋ฅด๊ณ ๊ฐ๋ ฅํ Next.js ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ ์ ์์ ๊ฑฐ์์.
์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์ฌ๋ฌ๋ถ์ Next.js ํ๋ก์ ํธ๋ฅผ ํ ๋จ๊ณ ๋ ๋ฐ์ ์์ผ ๋ณด์๊ธธ ๋ฐ๋๋๋ค!
๐ฎ ์ฐธ๊ณ
์ฐ๊ด๋ ํฌ์คํธ
๋จ์ด: 1,863๊ฐ22๋ถ[๐ค] React ๋ ๋๋ง ์ต์ ํ: useMemo, useCallback, React.memo ์๋ฒฝ ๊ฐ์ด๋
์ด์ค๊ธ ๊ฐ๋ฐ์๋ฅผ ์ํ React ๋ ๋๋ง ์ต์ ํ ๊ฐ์ด๋. useMemo, useCallback, React.memo์ ์ ํํ ์ฌ์ฉ๋ฒ๊ณผ ์ค๋ฌด์์ ํํ ์ ์ง๋ฅด๋ ์ค์, ๊ทธ๋ฆฌ๊ณ ์ค์ ์ฑ๋ฅ ํฅ์ ์ ๋ต์ ๋ธ๋ฃจ๊ฐ ์๋ ค๋๋ ค์.
๋จ์ด: 2,122๊ฐ24๋ถ[๐ค] JavaScript Proxy์ Reflect ์ฌ์ธต ๋ถ์: ๋ฉํ ํ๋ก๊ทธ๋๋ฐ์ผ๋ก ์ฝ๋ ๊ฐํํ๊ธฐ
JavaScript Proxy์ Reflect API๋ฅผ ํ์ฉํ ๋ฉํ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ์ฌ์ธต ๋ถ์ํด์. ๊ฐ์ฒด ์ ๊ทผ ์ ์ด, ์ ํจ์ฑ ๊ฒ์ฌ, ๋ก๊น , ๋ฐ์ํ ์์คํ ๊ตฌํ ๋ฑ ์ค์ฉ์ ์ธ ํ์ฉ ์ฌ๋ก๋ฅผ ํตํด ์ฝ๋์ ์ ์ฐ์ฑ๊ณผ ์์ ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.
- ๋จ์ด: 2,019๊ฐ24๋ถ
[๐ค] React/Next.js ๋ฒ๋ค ์ต์ ํ: ์ฝ๋ ์คํ๋ฆฌํ ๊ณผ ๋ ์ด์ง ๋ก๋ฉ ์๋ฒฝ ๊ฐ์ด๋
React์ Next.js ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ๋ก๋ฉ ์๋๋ฅผ ๊ฐ์ ํ๋ ์ฝ๋ ์คํ๋ฆฌํ ๊ณผ ๋ ์ด์ง ๋ก๋ฉ ๊ธฐ๋ฒ์ ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ์์ธํ ์์๋ด์. ์นํฉ ์ค์ ๋ถํฐ React.lazy, Next.js dynamic import๊น์ง ๋ค๋ค์.
- ๋จ์ด: 1,769๊ฐ20๋ถ
[๐ค] React์ `useOptimistic` ํ ์ผ๋ก ๋๊ด์ UI ์ ๋ฐ์ดํธ ๊ตฌํํ๊ธฐ: Server Actions์ ํจ๊ป
React 18/19์ `useOptimistic` ํ ์ ํ์ฉํ์ฌ Server Actions์ ์ฐ๋๋๋ ๋๊ด์ UI ์ ๋ฐ์ดํธ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ์์ธํ ์์๋ด์. ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์์ฑ์ ๋์ด๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํด์.
๋จ์ด: 1,557๊ฐ17๋ถ[๐ค] TypeScript const Type Parameters: ๋ฆฌํฐ๋ด ํ์ ์ถ๋ก ๊ฐํ์ ์ค์ฉ์ ์ธ ํ์ฉ๋ฒ
TypeScript 5.0์ ๋์ ๋ const Type Parameters๋ฅผ ํ์ฉํ์ฌ ์ ๋ค๋ฆญ ํจ์์ ๋ฆฌํฐ๋ด ํ์ ์ถ๋ก ์ ์ ๊ตํ๊ฒ ์ ์ดํ๊ณ , ๋์ฑ ๊ฒฌ๊ณ ํ ํ์ ์์คํ ์ ๊ตฌ์ถํ๋ ์ค์ฉ์ ์ธ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. as const์์ ์ฐจ์ด์ ๊ณผ ์ค์ ์ฝ๋ ์์๋ฅผ ํตํด ์ด์ค๊ธ ๊ฐ๋ฐ์๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋๋ก ์ค๋ช ํด ๋๋ ค์.
- ๋จ์ด: 2,015๊ฐ22๋ถ
[๐ค] Next.js/React ์ฑ CLS ์ต์ ํ: ์ํํธ ์๋ ์ฌ์ฉ์ ๊ฒฝํ ๋ง๋ค๊ธฐ
Next.js์ React ์ ํ๋ฆฌ์ผ์ด์ ์์ Cumulative Layout Shift(CLS) ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๋ ์ค์ง์ ์ธ ์ ๋ต๊ณผ ์ฝ๋ ์์๋ฅผ ์์ธํ ์์๋ณด์ธ์. ์น ์ฑ๋ฅ ์ต์ ํ์ ํต์ฌ ์์์ธ CLS๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,735๊ฐ21๋ถ
[๐ค] Next.js SSR, SSG, ISR ๋ ๋๋ง ์ ๋ต: App Router์์ ์ต์ ์ ์ ํ์?
Next.js App Router์์ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR), ์ ์ ์ฌ์ดํธ ์์ฑ(SSG), ์ฆ๋ถ ์ ์ ์ฌ์์ฑ(ISR) ๊ฐ ๋ ๋๋ง ์ ๋ต์ ๋์ ์๋ฆฌ, ์ฅ๋จ์ , ์ค์ ํ์ฉ ๋ฐ ์ต์ ํ ๋ฐฉ๋ฒ์ ๋น๊ต ๋ถ์ํด๋๋ ค์.
- ๋จ์ด: 1,460๊ฐ17๋ถ
[๐ค] React Context API์ Zustand: ์ ์ญ ์ํ ๊ด๋ฆฌ, ์ธ์ ๋ฌด์์ ์จ์ผ ํ ๊น์?
React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ญ ์ํ ๊ด๋ฆฌ๋ฅผ ๊ณ ๋ฏผํ๊ณ ๊ณ์ ๊ฐ์? Context API์ ๊ฐ๋ฒผ์ด ์ธ๋ถ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Zustand๋ฅผ ๋น๊ต ๋ถ์ํ๊ณ , ์ค๋ฌด์์ ๊ฐ ๋๊ตฌ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ์ ๋ต์ ์ค์ ์ฝ๋ ์์์ ํจ๊ป ์์ธํ ์๋ ค๋๋ ค์.
- ๋จ์ด: 2,004๊ฐ24๋ถ
[๐ค] Turborepo๋ก Next.js ๋ชจ๋ ธ๋ ํฌ ๊ตฌ์ถ: ํจ์จ์ ์ธ ๊ฐ๋ฐ ๋ฐ ์ต์ ํ ์ ๋ต
Turborepo๋ฅผ ํ์ฉํ์ฌ Next.js ํ๋ก์ ํธ๋ฅผ ๋ชจ๋ ธ๋ ํฌ๋ก ๊ตฌ์ฑํ๊ณ , ๊ณต์ ์ปดํฌ๋ํธ, ์ ํธ๋ฆฌํฐ, CI/CD ์ต์ ํ ๋ฐฉ์์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์ค๋ช ํด ๋๋ ค์.
- ๋จ์ด: 2,318๊ฐ27๋ถ
[๐ค] React useEffect ํ , ์ด์ ํท๊ฐ๋ฆฌ์ง ๋ง์ธ์! (์์กด์ฑ ๋ฐฐ์ด, ํด๋ฆฐ์ ์๋ฒฝ ๊ฐ์ด๋)
React ๊ฐ๋ฐ์์ ํ์์ ์ธ useEffect ํ ์ ๋์ ์๋ฆฌ๋ถํฐ ์์กด์ฑ ๋ฐฐ์ด, ํด๋ฆฐ์ ํจ์ ํ์ฉ๋ฒ, ๊ทธ๋ฆฌ๊ณ ์ค๋ฌด์์ ์์ฃผ ๊ฒช๋ ์ค์์ ์ต์ ํ ์ ๋ต๊น์ง, ์ด์ค๊ธ ๊ฐ๋ฐ์๋ฅผ ์ํ ์๋ฒฝ ๊ฐ์ด๋๋ฅผ ์ ๊ณตํด์.
- ๋จ์ด: 3,270๊ฐ31๋ถ
[๐ค] Next.js Server Actions ์ค์ : ์๋ฌ ์ฒ๋ฆฌ, ์ ํจ์ฑ ๊ฒ์ฌ, ๋๊ด์ UI ์ ๋ฐ์ดํธ
Next.js Server Actions๋ฅผ ์ค๋ฌด์ ์ ์ฉํ ๋ ๋ง์ฃผํ๋ ์๋ฌ ์ฒ๋ฆฌ, ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ๋๊ด์ UI ์ ๋ฐ์ดํธ ๊ธฐ๋ฒ์ ์์ธํ ์ฝ๋ ์์์ ํจ๊ป ์์๋ณด์ธ์.
๋จ์ด: 1,981๊ฐ21๋ถ[๐ค] TypeScript ์ ํธ๋ฆฌํฐ ํ์ ์๋ฒฝ ๊ฐ์ด๋: ์ค์ ํ์ฉ ํจํด
TypeScript ์ ํธ๋ฆฌํฐ ํ์ ์ ํต์ฌ ๊ฐ๋ ๊ณผ ์ค์ ํ์ฉ๋ฒ์ ๊น์ด ์๊ฒ ๋ค๋ค์. Pick, Omit, Partial, Required ๋ฑ ์์ฃผ ์ฐ๋ ์ ํธ๋ฆฌํฐ ํ์ ์ผ๋ก ๋ณต์กํ ํ์ ์ ํจ๊ณผ์ ์ผ๋ก ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์. ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ๊ณผ ์์ ์ฑ์ ๋์ด๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํด์.
- ๋จ์ด: 1,707๊ฐ20๋ถ
[๐ค] Next.js App Router ๋ฏธ๋ค์จ์ด: ๊ฐ๋ ฅํ ์์ฒญ ์ฒ๋ฆฌ ์ ๋ต๊ณผ ์ค์ ์์
Next.js App Router ํ๊ฒฝ์์ ๋ฏธ๋ค์จ์ด๋ฅผ ํ์ฉํด ์ฌ์ฉ์ ์ธ์ฆ, ๋ฆฌ๋ค์ด๋ ์ , ๊ตญ์ ํ ๋ฑ์ ์์ฒญ ์ฒ๋ฆฌ ๋ก์ง์ ํจ์จ์ ์ผ๋ก ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ค์ ์์ ์ ํจ๊ป ์์ธํ ์์๋ณด์ธ์.
- ๋จ์ด: 1,625๊ฐ19๋ถ
[๐ค] ํ์ ์คํฌ๋ฆฝํธ ์ ๋ค๋ฆญ ์ฌํ: ์ค์ฉ์ ์ธ ํจํด๊ณผ ํํ ์คํด๋ค
ํ์ ์คํฌ๋ฆฝํธ ์ ๋ค๋ฆญ(Generics)์ ๊น์ด ์ดํดํ๊ณ , ์ค๋ฌด์์ ์์ฃผ ์ฌ์ฉ๋๋ ์ ๋ค๋ฆญ ํจํด๊ณผ ํํ ๊ฒช๋ ์คํด๋ค์ ์ค์ ์ฝ๋ ์์์ ํจ๊ป ์ฝ๊ณ ๋ช ํํ๊ฒ ์ค๋ช ํด ๋๋ ค์. ํ์ ์์ ์ฑ๊ณผ ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.
๋จ์ด: 1,846๊ฐ18๋ถ[๐ค] Next.js Route Handler: App Router์์ ์์ ํ๊ณ ํจ์จ์ ์ธ API ๊ตฌ์ถํ๊ธฐ (์ธ์ฆ, ์๋ฌ ์ฒ๋ฆฌ ํฌํจ)
Next.js App Router์ Route Handler๋ฅผ ์ฌ์ฉํ์ฌ API ์๋ํฌ์ธํธ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ์์๋ด์. ์ธ์ฆ, ์๋ฌ ์ฒ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ์บ์ฑ ์ ๋ต์ ํฌํจํ ์ค์ฉ์ ์ธ ํ์ผ๋ก ์์ ํ๊ณ ํจ์จ์ ์ธ ์๋ฒ๋ฆฌ์ค ํจ์๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ตํ๋ด์.
- ๋จ์ด: 1,932๊ฐ22๋ถ
[๐ค] Next.js Image ์ปดํฌ๋ํธ ์ต์ ํ: Core Web Vitals ๊ฐ์ ๋ถํฐ ์ค์ ํ์ฉ๊น์ง
Next.js์ Image ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํ์ฌ ์น ์ฑ๋ฅ ํต์ฌ ์งํ์ธ Core Web Vitals๋ฅผ ๊ฐ์ ํ๊ณ , ๋ค์ํ ์ต์ ํ ์ต์ ์ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ธ๋ฃจ๊ฐ ์์ธํ ์๋ ค๋๋ ค์.
- ๋จ์ด: 2,173๊ฐ25๋ถ
[๐ค] Next.js 14.1+์ ํ์ : Partial Prerendering (PPR) ์๋ฒฝ ๊ฐ์ด๋์ ์ค์ ์ต์ ํ ์ ๋ต
Next.js 14.1๋ถํฐ ๋์ ๋ Partial Prerendering (PPR)์ ํตํด ์ด๊ธฐ ๋ก๋ฉ ์๋๋ฅผ ๊ทน๋ํํ๊ณ ๋์ ์ฝํ ์ธ ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ ์๊ฒ ๋ค๋ฃจ์ด์. PPR์ ๋์ ์๋ฆฌ๋ถํฐ ์ค์ ํ๋ก์ ํธ ์ ์ฉ ์ ๋ต๊น์ง, ๊ฐ๋ฐ์๋ค์ด ๊ถ๊ธํดํ๋ ๋ชจ๋ ๊ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 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๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์์๋ณด๊ณ ์น ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.