[๐Ÿค–] Next.js App Router์—์„œ Server Components์™€ Client Components ์ œ๋Œ€๋กœ ํ™œ์šฉํ•˜๊ธฐ

Next.js 13+ App Router ํ™˜๊ฒฝ์—์„œ Server Components์™€ Client Components์˜ ๊ฐœ๋…, ์ฐจ์ด์ , ๊ทธ๋ฆฌ๊ณ  ์‹ค์šฉ์ ์ธ ํ™œ์šฉ ์ „๋žต์„ ์ƒ์„ธํžˆ ์•Œ์•„๋ณด๊ณ , ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ๊ฐœ๋ฐœ ํšจ์œจ์„ฑ์„ ๋†’์ด๋Š” ๋ฐฉ๋ฒ•์„ ๊ณต์œ ํ•ด์š”.

15๋ถ„
๋‹จ์–ด: 1,271๊ฐœ
๊ฒŒ์‹œ๊ธ€ ์ธ๋„ค์ผ
์ •๋ณด

Next.js 13+ App Router์˜ ํ•ต์‹ฌ์ธ Server Components์™€ Client Components๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ณ  ํ™œ์šฉํ•˜์—ฌ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ๊ณผ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ๊ทน๋Œ€ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ•จ๊ป˜ ํƒ๊ตฌํ•ด์š”.
์šฐ๋ฆฌ๋Š” Server Components๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๊ณ , ํ•„์š”ํ•œ ๊ณณ์—๋งŒ Client Components๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ ํ™”๋œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ์ „๋žต์„ ๋ฐฐ์›Œ๋ณผ ๊ฑฐ์˜ˆ์š”.

๐Ÿค” ๋ฌธ์ œ/๋ฐฐ๊ฒฝ

0๏ธโƒฃ ์™œ ์ด ์ฃผ์ œ๋ฅผ ๋‹ค๋ฃจ๋Š”๊ฐ€์š”?

Next.js 13๋ถ€ํ„ฐ ๋„์ž…๋œ App Router๋Š” ๊ธฐ์กด Pages Router์™€๋Š” ๊ทผ๋ณธ์ ์œผ๋กœ ๋‹ค๋ฅธ ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์ œ์‹œํ–ˆ์–ด์š”.
ํŠนํžˆ Server Components๋Š” React์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์œผ๋กœ, ๋ฐฑ์—”๋“œ ๋กœ์ง๊ณผ ํ”„๋ก ํŠธ์—”๋“œ UI๋ฅผ ํ†ตํ•ฉํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๊ฐ€๋Šฅ์„ฑ์„ ์—ด์–ด์ฃผ์—ˆ์ฃ .
ํ•˜์ง€๋งŒ ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋ถ„๋“ค์ด Server Components์™€ Client Components์˜ ์ •ํ™•ํ•œ ์ฐจ์ด์ , ๊ทธ๋ฆฌ๊ณ  ์–ธ์ œ ๋ฌด์—‡์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ํ˜ผ๋ž€์„ ๊ฒช๊ณ  ๊ณ„์„ธ์š”.
์ด๋Ÿฌํ•œ ํ˜ผ๋ž€์€ ๋ถˆํ•„์š”ํ•œ Client Component ์‚ฌ์šฉ์œผ๋กœ ์ด์–ด์ ธ Next.js๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ด์ ์„ ์ œ๋Œ€๋กœ ๋ˆ„๋ฆฌ์ง€ ๋ชปํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”.

1๏ธโƒฃ ๊ธฐ์กด ๋ฐฉ์‹์˜ ํ•œ๊ณ„ (๋˜๋Š” ์˜คํ•ด)

๊ธฐ์กด Pages Router๋‚˜ ๋‹ค๋ฅธ SPA(Single Page Application) ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋™์ž‘ํ–ˆ์–ด์š”.
์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR)์„ ์‚ฌ์šฉํ•˜๋”๋ผ๋„, ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋งŒ ์„œ๋ฒ„์—์„œ ์ƒ์„ฑ๋  ๋ฟ, ์ดํ›„์˜ ๋ชจ๋“  ์ธํ„ฐ๋ž™์…˜์€ ํด๋ผ์ด์–ธํŠธ JavaScript์— ์˜์กดํ–ˆ์ฃ .
์ด๋กœ ์ธํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์–ด์š”.

  • ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ์ฆ๊ฐ€: ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์˜ JavaScript ์ฝ”๋“œ๊ฐ€ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋˜์–ด์•ผ ํ–ˆ์–ด์š”. ํŠนํžˆ, ์ธํ„ฐ๋ž™์…˜์ด ์—†๋Š” ์ •์ ์ธ UI๊นŒ์ง€๋„์š”.
  • ๋ฐ์ดํ„ฐ ํŽ˜์นญ์˜ ๋ณต์žก์„ฑ: ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•˜๊ฑฐ๋‚˜, ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•˜๋ ค๋ฉด getServerSideProps๋‚˜ getStaticProps ๊ฐ™์€ ํŠน๋ณ„ํ•œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ์–ด์š”. ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ–ˆ์ฃ .
  • ์ดˆ๊ธฐ ๋กœ๋”ฉ ์„ฑ๋Šฅ ์ €ํ•˜: ํด๋ผ์ด์–ธํŠธ JavaScript ๋ฒˆ๋“ค์ด ๋‹ค์šด๋กœ๋“œ๋˜๊ณ  ์‹คํ–‰๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ƒํ˜ธ์ž‘์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ–ˆ์–ด์š”.

App Router๊ฐ€ ๋„์ž…๋˜๋ฉด์„œ Server Components๊ฐ€ ๊ธฐ๋ณธ๊ฐ’์ด๋ผ๋Š” ์ ์„ ๊ฐ„๊ณผํ•˜๊ณ , ๊ด€์„ฑ์ ์œผ๋กœ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— "use client"; ์ง€์‹œ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„์š”.
์ด๋Š” Server Components์˜ ์žฅ์ ์„ ํฌ๊ธฐํ•˜๊ณ  ๋‹ค์‹œ ๊ธฐ์กด์˜ SPA ๋ฐฉ์‹์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฆ„์—†์–ด์š”.

๊ฒฝ๊ณ 

๋ถˆํ•„์š”ํ•˜๊ฒŒ "use client";๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ Server Components์˜ ํ•ต์‹ฌ ์ด์ ์ธ ๋ฒˆ๋“ค ํฌ๊ธฐ ๊ฐ์†Œ์™€ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„ ํ–ฅ์ƒ์„ ์ €ํ•ดํ•  ์ˆ˜ ์žˆ์–ด์š”.
ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ํ•ญ์ƒ JavaScript ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์–ด ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

โš™๏ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

0๏ธโƒฃ ํ•ต์‹ฌ ์•„์ด๋””์–ด: Server First ์ „๋žต

Next.js App Router์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋Š” "Server First" ์›์น™์ด์—์š”.
๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” Server Component๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ ์ธก ์ƒํ˜ธ์ž‘์šฉ(useState, useEffect, onClick ๋“ฑ)์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋ช…์‹œ์ ์œผ๋กœ Client Component๋กœ ์ „ํ™˜ํ•˜๋ผ๋Š” ์˜๋ฏธ์˜ˆ์š”.
์ด๊ฒƒ์ด ๋ฐ”๋กœ "use client"; ์ง€์‹œ์–ด๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ์ฃ .

Server Components (๊ธฐ๋ณธ๊ฐ’):

  • ์–ด๋””์„œ ๋ Œ๋”๋ง๋ ๊นŒ์š”? ์„œ๋ฒ„์—์„œ๋งŒ ๋ Œ๋”๋ง๋ผ์š”.
  • ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ง์ ‘ ์ ‘๊ทผ, ํŒŒ์ผ ์‹œ์Šคํ…œ ์ ‘๊ทผ, API ํ‚ค์™€ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด ์‚ฌ์šฉ ๋“ฑ ์„œ๋ฒ„ ์ „์šฉ ๋กœ์ง์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋ ๊นŒ์š”? JavaScript ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š๊ณ , ๋ Œ๋”๋ง๋œ HTML๋งŒ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋ผ์š”. (๋”ฐ๋ผ์„œ ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๊ฐ€ ์ค„์–ด๋“ค์ฃ !)
  • ๋ฌด์—‡์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์„๊นŒ์š”? useState, useEffect, onClick๊ณผ ๊ฐ™์€ React ํ›…์ด๋‚˜ ๋ธŒ๋ผ์šฐ์ € API(window, document)๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์š”.
  • ์–ธ์ œ ์‚ฌ์šฉํ• ๊นŒ์š”? ๋ฐ์ดํ„ฐ ํŽ˜์นญ, ์ •์ ์ธ UI ๋ Œ๋”๋ง, SEO ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•œ ํŽ˜์ด์ง€, ๋ฐฑ์—”๋“œ ๋กœ์ง๊ณผ ๋ฐ€์ ‘ํ•œ ์ปดํฌ๋„ŒํŠธ ๋“ฑ์— ์ ํ•ฉํ•ด์š”.

Client Components ("use client";):

  • ์–ด๋””์„œ ๋ Œ๋”๋ง๋ ๊นŒ์š”? ํด๋ผ์ด์–ธํŠธ(๋ธŒ๋ผ์šฐ์ €)์—์„œ ๋ Œ๋”๋ง๋ผ์š”. (์ดˆ๊ธฐ ๋ Œ๋”๋ง์€ ์„œ๋ฒ„์—์„œ ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ดํ›„ ํ•˜์ด๋“œ๋ ˆ์ด์…˜ ๋ฐ ์ƒํ˜ธ์ž‘์šฉ์€ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋‹ด๋‹นํ•ด์š”.)
  • ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? useState, useEffect, useRef, onClick ๋“ฑ์˜ React ํ›…๊ณผ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ, ๊ทธ๋ฆฌ๊ณ  ๋ธŒ๋ผ์šฐ์ € API์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋ ๊นŒ์š”? JavaScript ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์–ด ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋ผ์š”.
  • ๋ฌด์—‡์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์„๊นŒ์š”? ์„œ๋ฒ„ ์ „์šฉ ๋กœ์ง(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ง์ ‘ ์ ‘๊ทผ ๋“ฑ)์„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์–ด์š”.
  • ์–ธ์ œ ์‚ฌ์šฉํ• ๊นŒ์š”? ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•œ UI (์นด์šดํ„ฐ, ํผ ์ž…๋ ฅ, ๋ชจ๋‹ฌ), ํด๋ผ์ด์–ธํŠธ ์ „์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (์ฐจํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ), Context API ์‚ฌ์šฉ ๋“ฑ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜๊ณผ ์ง์ ‘ ๊ด€๋ จ๋œ ๋ถ€๋ถ„์— ์ ํ•ฉํ•ด์š”.

1๏ธโƒฃ ์ ์šฉ ๋ฐฉ๋ฒ•: ๊ฒฝ๊ณ„ ๋ช…ํ™•ํ™”์™€ ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ

์„ฑ๊ณต์ ์ธ Server/Client Component ํ™œ์šฉ์€ ์ด ๋‘˜์˜ ๊ฒฝ๊ณ„๋ฅผ ๋ช…ํ™•ํžˆ ํ•˜๊ณ , ์—ญํ• ์„ ์ ์ ˆํžˆ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐ ๋‹ฌ๋ ค์žˆ์–ด์š”.

  1. "Server First" ๋งˆ์ธ๋“œ์…‹: ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ํ•ญ์ƒ Server Component๋กœ ์‹œ์ž‘ํ•˜์„ธ์š”. ํด๋ผ์ด์–ธํŠธ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๋ช…ํ™•ํ•œ ์ด์œ ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ "use client";๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฐ์ดํ„ฐ ํŽ˜์นญ์€ Server Component์—์„œ: ๊ฐ€๋Šฅํ•œ ํ•œ ๋ฐ์ดํ„ฐ ํŽ˜์นญ์€ Server Component์—์„œ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์—์„œ ๋ฐ์ดํ„ฐ ํŽ˜์นญ ๋กœ์ง์„ ์ œ๊ฑฐํ•˜๊ณ , ๋ถˆํ•„์š”ํ•œ API ํ˜ธ์ถœ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ค„์ด์„ธ์š”.
  3. Client Component๋Š” 'Leaf' ๋…ธ๋“œ๋กœ: ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•œ Client Component๋Š” ๋˜๋„๋ก ํŠธ๋ฆฌ ๊ตฌ์กฐ์˜ ๊ฐ€์žฅ ํ•˜์œ„(Leaf) ๋…ธ๋“œ์— ๋ฐฐ์น˜ํ•˜์„ธ์š”.
    Server Component ์•ˆ์— Client Component๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Client Component ์•ˆ์— Server Component๋ฅผ ์ง์ ‘ ๋ Œ๋”๋งํ•  ์ˆ˜๋Š” ์—†์–ด์š”.
    (Server Component๋Š” Client Component์˜ props๋กœ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ž์‹์œผ๋กœ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์—์š”.)
  4. Props๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ: Server Component์—์„œ ํŽ˜์นญํ•œ ๋ฐ์ดํ„ฐ๋ฅผ Client Component๋กœ props๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์–ด์š”.
    ์ด๋•Œ ์ „๋‹ฌ๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ์ง๋ ฌํ™” ๊ฐ€๋Šฅํ•œ(serializable) ํ˜•ํƒœ์—ฌ์•ผ ํ•ด์š”.
์œ ์šฉํ•œ ํŒ

"use client"; ์ง€์‹œ์–ด๋Š” ํŒŒ์ผ์˜ ๋งจ ์œ„์— ํ•œ ๋ฒˆ๋งŒ ์„ ์–ธํ•˜๋ฉด ํ•ด๋‹น ํŒŒ์ผ ๋‚ด์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์™€ ๋ชจ๋“ˆ์ด Client Component๋กœ ์ฒ˜๋ฆฌ๋ผ์š”.
๋”ฐ๋ผ์„œ ์ž‘์€ ๋‹จ์œ„์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ Client Component๋ฅผ ๋งŒ๋“ค๊ณ , ์ด๋ฅผ Server Component์—์„œ ๋ถˆ๋Ÿฌ์™€ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ์ „๋žต์ด์—์š”.

๐Ÿงช ์˜ˆ์‹œ

0๏ธโƒฃ ์ฝ”๋“œ/์„ค์ • ์˜ˆ์‹œ

๋‹ค์Œ์€ Server Components์™€ Client Components๋ฅผ ํ™œ์šฉํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ด์—์š”.

1. Server Component (๋ฐ์ดํ„ฐ ํŽ˜์นญ) app/dashboard/page.tsx

import { fetchRecentOrders } from '../lib/data'; // ์„œ๋ฒ„์—์„œ๋งŒ ์‚ฌ์šฉ๋  ๋ฐ์ดํ„ฐ ํŽ˜์นญ ํ•จ์ˆ˜ // ์ด ์ปดํฌ๋„ŒํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Server Component์ž…๋‹ˆ๋‹ค. export default async function DashboardPage() { const orders = await fetchRecentOrders(); // ์„œ๋ฒ„์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ ํŽ˜์นญ // console.log(process.env.DATABASE_URL); // ์„œ๋ฒ„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ ‘๊ทผ ๊ฐ€๋Šฅ return ( <section> <h1>๋Œ€์‹œ๋ณด๋“œ</h1> <p>์ตœ๊ทผ ์ฃผ๋ฌธ ๋ชฉ๋ก:</p> <ul> {orders.map((order: any) => ( <li key={order.id}>{order.productName} - {order.amount}์›</li> ))} </ul> {/* Client Component๋ฅผ ์ž์‹์œผ๋กœ ํฌํ•จํ•  ์ˆ˜ ์žˆ์–ด์š” */} <InteractiveButton /> </section> ); }

2. Client Component (์ƒํ˜ธ์ž‘์šฉ) app/dashboard/InteractiveButton.tsx

"use client"; // ์ด ํŒŒ์ผ์€ Client Component์ž„์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. import { useState } from 'react'; export default function InteractiveButton() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(count + 1)}> ํด๋ฆญ ํšŸ์ˆ˜: {count} </button> ); }

3. Server Component๊ฐ€ Client Component์— ๋ฐ์ดํ„ฐ ์ „๋‹ฌ app/product/[id]/page.tsx

import { fetchProductDetail } from '@/lib/api'; import AddToCartButton from './AddToCartButton'; // Client Component ์ž„ํฌํŠธ export default async function ProductDetailPage({ params }: { params: { id: string } }) { const product = await fetchProductDetail(params.id); if (!product) { return <div>์ƒํ’ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์–ด์š”.</div>; } return ( <div> <h1>{product.name}</h1> <p>{product.description}</p> <p>๊ฐ€๊ฒฉ: {product.price}์›</p> {/* Server Component๊ฐ€ Client Component์— props๋ฅผ ์ „๋‹ฌํ•ด์š” */} <AddToCartButton productId={product.id} productName={product.name} /> </div> ); }

app/product/[id]/AddToCartButton.tsx

"use client"; import { useState } from 'react'; interface AddToCartButtonProps { productId: string; productName: string; } export default function AddToCartButton({ productId, productName }: AddToCartButtonProps) { const [quantity, setQuantity] = useState(1); const handleAddToCart = () => { // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋กœ์ง (ํด๋ผ์ด์–ธํŠธ์—์„œ ๋™์ž‘) console.log(`${productName} (ID: ${productId}) ${quantity}๊ฐœ๋ฅผ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด์•˜์–ด์š”.`); alert(`${productName} ${quantity}๊ฐœ๊ฐ€ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ถ”๊ฐ€๋˜์—ˆ์–ด์š”!`); }; return ( <div> <input type="number" min="1" value={quantity} onChange={(e) => setQuantity(Number(e.target.value))} /> <button onClick={handleAddToCart}>์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ถ”๊ฐ€</button> </div> ); }

1๏ธโƒฃ ์ ์šฉ ๊ฒฐ๊ณผ ๋ฐ ๊ณ ๋ ค์‚ฌํ•ญ

์œ„ ์˜ˆ์‹œ์ฒ˜๋Ÿผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ์–ด์š”.

  • ์„ฑ๋Šฅ ํ–ฅ์ƒ: DashboardPage์™€ ProductDetailPage๋Š” Server Component์ด๋ฏ€๋กœ, ๋ฐ์ดํ„ฐ ํŽ˜์นญ ๋กœ์ง์ด ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š์•„์š”.
    ํด๋ผ์ด์–ธํŠธ๋Š” ์ตœ์†Œํ•œ์˜ JavaScript (์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•œ InteractiveButton๊ณผ AddToCartButton์˜ ์ฝ”๋“œ๋งŒ)๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ฒŒ ๋˜์–ด ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„๊ฐ€ ๋นจ๋ผ์ ธ์š”.
  • SEO ์ตœ์ ํ™”: ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋œ HTML์ด ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋˜๋ฏ€๋กœ, ๊ฒ€์ƒ‰ ์—”์ง„ ํฌ๋กค๋Ÿฌ๊ฐ€ ํŽ˜์ด์ง€ ์ฝ˜ํ…์ธ ๋ฅผ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ๋ณด์•ˆ ๊ฐ•ํ™”: ๋ฏผ๊ฐํ•œ API ํ‚ค๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ ๋กœ์ง์€ Server Component ๋‚ด๋ถ€์— ์•ˆ์ „ํ•˜๊ฒŒ ์œ ์ง€๋  ์ˆ˜ ์žˆ์–ด์š”.
  • ๊ฐœ๋ฐœ ๊ฒฝํ—˜: async/await๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ํŽ˜์นญ์„ ์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ์—์„œ ์ง์ ‘ ํ•  ์ˆ˜ ์žˆ์–ด, ๊ธฐ์กด getServerSideProps์™€ ๊ฐ™์€ ํŠน์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ง๊ด€์ ์ด์—์š”.
์ •๋ณด

Server Component์˜ Props ์ง๋ ฌํ™”: Server Component์—์„œ Client Component๋กœ ์ „๋‹ฌํ•˜๋Š” props๋Š” ์ง๋ ฌํ™” ๊ฐ€๋Šฅํ•œ(serializable) ๊ฐ’์ด์–ด์•ผ ํ•ด์š”.
ํ•จ์ˆ˜๋‚˜ ์‹ฌ๋ณผ, ๋‚ ์งœ ๊ฐ์ฒด ๊ฐ™์€ ์ง๋ ฌํ™” ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฐ’์€ Client Component๋กœ ์ง์ ‘ ์ „๋‹ฌ๋  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์„ธ์š”.

๐Ÿ“ ์ •๋ฆฌ

0๏ธโƒฃ ํ•ต์‹ฌ ์š”์•ฝ

Next.js App Router์—์„œ Server Components์™€ Client Components๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ๊ณผ ๊ตฌ์กฐ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ํ•ต์‹ฌ ์š”์†Œ์˜ˆ์š”.

  • Server Components: ๊ธฐ๋ณธ๊ฐ’์ด๋ฉฐ, ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋˜์–ด JavaScript ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š๊ณ , ๋ฐ์ดํ„ฐ ํŽ˜์นญ๊ณผ ๋ฐฑ์—”๋“œ ๋กœ์ง์— ์ ํ•ฉํ•ด์š”.
  • Client Components: "use client"; ์ง€์‹œ์–ด๋ฅผ ํ†ตํ•ด ๋ช…์‹œํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ์—์„œ ์ƒํ˜ธ์ž‘์šฉ(ํ›…, ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ)์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ € API์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์š”.

"Server First" ์›์น™์„ ๋”ฐ๋ผ ๊ฐ€๋Šฅํ•œ ํ•œ Server Component๋ฅผ ํ™œ์šฉํ•˜๊ณ , ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ๋ถ€๋ถ„์—๋งŒ Client Component๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์€ ์ „๋žต์ด์—์š”. ์ด๋Š” ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ๊ฐ์†Œ, ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„ ํ–ฅ์ƒ, SEO ์ตœ์ ํ™”, ๊ทธ๋ฆฌ๊ณ  ๋ณด์•ˆ ๊ฐ•ํ™”๋กœ ์ด์–ด์ ธ์š”.

1๏ธโƒฃ ๋‹ค์Œ ์•ก์…˜

์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ธฐ์กด Next.js ํ”„๋กœ์ ํŠธ์˜ ์ปดํฌ๋„ŒํŠธ๋“ค์„ Server Component์™€ Client Component๋กœ ์–ด๋–ป๊ฒŒ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์„์ง€ ๊ณ ๋ฏผํ•ด๋ณด์„ธ์š”.
์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค๋ฉด, Server First ๋งˆ์ธ๋“œ์…‹์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ , ๋ถˆํ•„์š”ํ•œ "use client"; ์‚ฌ์šฉ์„ ์ง€์–‘ํ•˜๋ฉฐ ์ตœ์ ํ™”๋œ Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•ด๋ณด์‹œ๊ธธ ๊ถŒํ•ด๋“œ๋ ค์š”.
๋” ๊นŠ์ด ์žˆ๋Š” ์ดํ•ด๋ฅผ ์œ„ํ•ด Next.js ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์˜ˆ์‹œ์™€ ํŒจํ„ด๋“ค์„ ํƒ์ƒ‰ํ•˜๋Š” ๊ฒƒ๋„ ์•„์ฃผ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์—์š”.

๐Ÿ“ฎ ์ฐธ๊ณ 

์—ฐ๊ด€๋œ ํฌ์ŠคํŠธ