๐Ÿ’ก 15. ์„œ๋ฒ„๋กœ ํšŒ๊ท€ํ•˜๋‹ค: RSC์™€ next.js ๋ธŒ๋ฆฟ์ง€

๐Ÿ“‹ ๊ฐœ์š”

React ์ƒํƒœ๊ณ„์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ณ€ํ™”์ธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ(RSC)์˜ ์˜๋ฏธ์™€, use client ์ง€์‹œ์–ด๊ฐ€ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ฒฝ๊ณ„์„ (Boundary) ์—ญํ• ์„ ์–ด๋–ป๊ฒŒ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ์ด์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • React Server Components(RSC)๊ฐ€ ๊ธฐ์กด์˜ SSR(Server-Side Rendering)๊ณผ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋งˆ๋ฒ•์ด๋ผ๋Š” ์ ์„ ์ดํ•ดํ•œ๋‹ค.
  • use client ์ตœ์ƒ๋‹จ ์ง€์‹œ์–ด์˜ ์ง„์งœ ์˜๋ฏธ๊ฐ€ '๋ธŒ๋ผ์šฐ์ € ์ „์šฉ ์‹คํ–‰'์ด ์•„๋‹ˆ๋ผ ๋‹จ์ ˆ์˜ ๊ฒฝ๊ณ„์„ (Network Boundary) ์ž„์„ ์™„๋ฒฝํžˆ ๊ทธ๋ ค๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ์˜ ์ฑ…์ž„ ์†Œ์žฌ์ง€(์„œ๋ฒ„๋ƒ, ํด๋ผ์ด์–ธํŠธ๋ƒ)๋ฅผ ๋ช…ํ™•ํžˆ ํŒ๋ณ„ํ•˜๋Š” ์‹œ๊ฐ์„ ๊ฐ–๋Š”๋‹ค. (๋Œ€๋‹จ์› ๋งˆ๋ฌด๋ฆฌ)

๐Ÿ“‹ ๋ชฉ์ฐจ


๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 10๋ถ„ / ํ•ต์‹ฌ ํŒŒํŠธ: 6๋ถ„

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

  • ์˜์ฒ (์‹ ์ž…):"์„ ๋ฐฐ๋‹˜! Next.js 13 ๋ฒ„์ „๋ถ€ํ„ฐ ๋งจ๋‚  ํŽ˜์ด์ง€ ์ƒ๋‹จ์— use client ์“ฐ๋ผ๊ณ  ์—๋Ÿฌ๊ฐ€ ๋– ์„œ ํ™”๊ฐ€ ๋‚˜ ์ฃฝ๊ฒ ์–ด์š”! ๊ทธ๋ƒฅ _app.tsx ์ ค ์œ„์— ํ•œ ๋ฒˆ ์ ์–ด๋‘๋ฉด ์ „๋ถ€ ํด๋ผ์ด์–ธํŠธ๋กœ ํŽธํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€์š”?"
  • ์˜ํ˜ธ(๋ฆฌ๋“œ):"์˜์ฒ  ๋‹˜. ๊ทธ๊ฑธ ์ „๋ถ€ ํด๋ผ์ด์–ธํŠธ๋กœ ๋Œ๋ ค๋ฒ„๋ฆด ๊ฑฐ๋ฉด ๋ฌด๊ฑฐ์šด ๋ฒˆ๋“ค ํŒŒ์ผ ์ˆ˜๋ฐฑ ๋ฉ”๊ฐ€๋ฅผ ์œ ์ € ๋ธŒ๋ผ์šฐ์ €์— ํˆฌ์ฒ™ํ•œ๋‹ค๋Š” ์†Œ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ 10๋…„ ๋งŒ์— ์ผ์–ด๋‚œ 'ํ”„๋ก ํŠธ์—”๋“œ์˜ ๋Œ€๋ฅ™ ์ด๋™(์„œ๋ฒ„์‚ฌ์ด๋“œ ์˜ํ†  ๊ท€ํ™˜)' ์˜ ํ•œ๊ฐ€์šด๋ฐ ์„œ ์žˆ์Šต๋‹ˆ๋‹ค."

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€: JS ๋ฒˆ๋“ค ๋‹ค์ด์–ดํŠธ์˜ ์ „์Ÿ

์ง€๊ธˆ๊นŒ์ง€ 01๊ฐ•๋ถ€ํ„ฐ 14๊ฐ•๊นŒ์ง€ ๋ฐฐ์šด ๋ชจ๋“  ๋‚ด์šฉ์€ ๋‹จ์„œ๋ฅผ ๋‹ฌ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
"์ด ์ฝ”๋“œ๋Š” ๋ธŒ๋ผ์šฐ์ €(ํฌ๋กฌ, ์‚ฌํŒŒ๋ฆฌ) ์œ„์—์„œ ์‹คํ–‰๋œ๋‹ค."

ํ•˜์ง€๋งŒ ์ƒ๊ฐํ•ด๋ณด์„ธ์š”. ๋‹น์‹ ์ด ๊ฑฐ๋Œ€ํ•œ ๋‚ ์”จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ moment.js (ํฌ๊ธฐ: 300KB)๋‚˜ Markdown ๋ Œ๋”๋ง ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์จ์„œ ํ™”๋ฉด์„ ๊ทธ๋ฆฐ๋‹ค๊ณ  ์นฉ์‹œ๋‹ค.
๊ธฐ์กด์˜ React ์ƒํƒœ๊ณ„(CSR, ์ „ํ†ต์  SPA)์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ์—์„œ ๋‚ด ์‚ฌ์ดํŠธ์— ๋“ค์–ด์˜ค์ž๋งˆ์ž ๊ทธ ๋ฌด๊ฑฐ์šด ์ฝ”๋”ฉ ํŒŒ์ผ 300KB๋ฅผ ๋ชฝ๋•… ๋‹ค์šด๋กœ๋“œํ•ด์•ผ ๋น„๋กœ์†Œ ์‹คํ–‰์ด ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. "๋กœ๋”ฉ ์ค‘..." ์Šคํ”ผ๋„ˆ๊ฐ€ ๋ฌดํ•œ์ • ๋ฑ…๊ธ€๋ฑ…๊ธ€ ๋•๋‹ˆ๋‹ค.

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
์ด๊ฑฐ ์šฐ๋ฆฌ ์ปดํ“จํ„ฐ(์„œ๋ฒ„) ์„ฑ๋Šฅ ์ข‹์€๋ฐ... ์šฐ๋ฆฌ๊ฐ€ ์„œ๋ฒ„์—์„œ ์ € ๋ฌด๊ฑฐ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ๋Œ๋ ค์„œ HTML๋งŒ ์˜ˆ์˜๊ฒŒ ๊นŽ์•„๋‚ธ ๋‹ค์Œ ๊ฒฐ๊ณผ๋ฌผ ํ…์ŠคํŠธ(๋ฌธ์ž์—ด)๋งŒ ํฐ์œผ๋กœ ๋˜์ ธ์ฃผ๋ฉด ์œ ์ € ๋ฐ์ดํ„ฐ(MB)๋„ ์•„๋ผ๊ณ  ๋กœ๋”ฉ๋„ 0.1์ดˆ ์ปท ์•„๋‹๊นŒ?

์˜ˆ. ๊ทธ ์ƒ๊ฐ์—์„œ ์ถœ๋ฐœํ•œ ๊ถ๊ทน์˜ ์ง„ํ™”๊ฐ€ ๋ฐ”๋กœ React Server Components (RSC) ์ž…๋‹ˆ๋‹ค.


๐Ÿ—๏ธ ๋น„์œ ๋กœ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ

๐Ÿง’ 5์‚ด์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๋ฉด?

  1. ๊ณผ๊ฑฐ (Client Component ์œ„์ฃผ ์‹œ๋Œ€):
    ์‹๋‹น ์š”๋ฆฌ์‚ฌ(์˜์ฒ )๊ฐ€ ์†๋‹˜(๋ธŒ๋ผ์šฐ์ €)์—๊ฒŒ ์ƒ๊ณ ๊ธฐ, ์•ผ์ฑ„, ์นผ, ๋„๋งˆ, ๊ฐ€์Šค๋ฒ„๋„ˆ(๊ฑฐ๋Œ€ํ•œ JS ๋ฒˆ๋“ค ์ฝ”๋“œ ๋ฉ์–ด๋ฆฌ)๋ฅผ ๋ฐ•์Šค ์ฑ„๋กœ ํ…Œ์ด๋ธ”์— ๋‹ค์งœ๊ณ ์งœ ๋˜์ ธ์คŒ.
    โ€œ์†๋‹˜! ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” ์†๋‹˜ ํœด๋Œ€ํฐ์ด ์ง์ ‘ ๊ฐ€์Šค๋ฒ„๋„ˆ ์ผœ๊ณ (useEffect), ๋„ค์ด๋ฒ„์— ๋‚ ์”จ ๋ฌผ์–ด๋ณด๊ณ (fetch), ๊ณ ๊ธฐ ๊ตฌ์›Œ์„œ ํ–„๋ฒ„๊ฑฐ ์กฐ๋ฆฝ(๋ Œ๋”๋ง)ํ•ด ๋“œ์„ธ์š”!โ€ -> ์œ ์ € ํฐ์ด ์—„์ฒญ ๋œจ๊ฑฐ์›Œ์ง€๊ณ  ๋กœ๋”ฉ์ด ๊น€.

  2. ํ˜„์žฌ (์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ, Server Components):
    ๊ฐ•๋ ฅํ•œ ์ฃผ๋ฐฉ(Node.js ์„œ๋ฒ„)์—์„œ ์š”๋ฆฌ์‚ฌ(์˜ํ˜ธ)๊ฐ€ ์—„์ฒญ ๋น ๋ฅธ ์†๋„๋กœ ๋‚ ์”จ๋„ ์•Œ์•„์˜ค๊ณ , ๊ณ ๊ธฐ๋„ ๋‹ค ๊ตฝ๊ณ  ๋งˆํฌ๋‹ค์šดํŒŒ์‹ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฒ˜๋ฆฌ๋„ ๋‹ค ๋๋ƒ„.
    ํ…Œ์ด๋ธ”(์œ ์ € ํฐ)์—๋Š” ๋ญ๋งŒ ๋ฐฐ๋‹ฌํ•ด์ฃผ๋А๋ƒ? ๋‹จ 0.01์ดˆ ๋งŒ์— ์ด์˜๊ฒŒ ์™„์„ฑ๋œ ํ–„๋ฒ„๊ฑฐ(์ •์ ์ธ HTML ๋ ˆ์ด์•„์›ƒ)๋งŒ ์‹ํƒ ์œ„์— ์‚ฌ๋ฟํžˆ ์˜ฌ๋ ค์คŒ.
    ์œ ์ €๋Š” ํŒŒ์ผ ์šฉ๋Ÿ‰์„ ๊ฑฐ์˜ ์•ˆ ๋ฐ›์•„๋„ ํ™”๋ฉด์„ ์ฆ‰๊ฐ(0์ดˆ ๋งŒ์—) ๋ณด๊ฒŒ ๋จ!

์ด ์—„์ฒญ๋‚œ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋•Œ๋ฌธ์— Next.js ๊ฐ™์€ ์‹ ๊ธฐ์ˆ  ์œ„์—์„œ๋Š” ์ด์ œ "๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋ณธ๊ฐ’(Default)์€ ๋ฌด์กฐ๊ฑด ์ฃผ๋ฐฉ(์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ)์—์„œ ๊ตฌ์›Œ์ง„๋‹ค" ๋กœ ๊ทœ์น™์ด ์™„์ „ํžˆ ๋’ค์ง‘ํžŒ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๐Ÿงฉ ๊ทน์˜ ์ฒด๋“: RSC์™€ use client์˜ ์ง„์งœ ์ž„๋ฌด

๊ทธ๋Ÿผ ์˜์ฒ ์ด์˜ ์งˆ๋ฌธ์œผ๋กœ ๋Œ์•„๊ฐ€ ๋ด…์‹œ๋‹ค. ์™œ ์ž๊พธ ์—๋Ÿฌ๊ฐ€ ๋‚˜๊ณ  use client๋ฅผ ๊ฐ•์ œํ–ˆ์„๊นŒ์š”?

์„œ๋ฒ„ ์ฃผ๋ฐฉ์—์„œ ์š”๋ฆฌ๋ฅผ ์•”๋งŒ ์ž˜ ๊ตฌ์›Œ์„œ ์คฌ์–ด๋„, "์†๋‹˜์ด ์ง์ ‘ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค ํญ์ฃฝ์ด ํ„ฐ์ง€๋Š” ๋ฐ˜์‘(onClick)" ์ด๋‚˜ "์†๋‹˜์˜ ์ง€๊ธˆ ํ˜„์žฌ ๋งˆ์šฐ์Šค ์œ„์น˜(useState)" ๋Š” ์„œ๋ฒ„ ์ฃผ๋ฐฉ์—์„œ ์•Œ ํ„ฑ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค!

โœ… 1. RSC์˜ ์ฒ ์น™ (์„œ๋ฒ„์˜ ์˜ํ† )

๊ธฐ๋ณธ์ ์œผ๋กœ ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์ ์œผ๋ฉด ๋ชฝ๋•… ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ž…๋‹ˆ๋‹ค.

// ๐ŸŽฏ ์ด๊ฑฐ์Šจ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ (Next.js 13+ App Router ๊ธฐ์ค€)
// ์ตœ์ƒ๋‹จ์— ์•„๋ฌด๊ฒƒ๋„ ์—†๋‹ค. ๊ณ ๋กœ ๋‚˜๋Š” ์„œ๋ฒ„์—์„œ ๋นš์–ด์ ธ ๋‚ด๋ ค๊ฐ„๋‹ค.
 
import fs from 'fs'; // ํ—‰! ๋ฆฌ์•กํŠธ ๋‚ด๋ถ€์—์„œ ๋””์Šคํฌ ํŒŒ์ผ ์ฝ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง!
import HeavyMarkdownToHtml from 'markdown-heavy-lib'; // 300MB์งœ๋ฆฌ ์ตœ์•…์˜ ๋ฌด๊ฑฐ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ!
 
// ํ—‰! ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ์•ž์— async๊ฐ€ ๋ถ™์–ด? (useEffect ์—†์ด await๋กœ API ์ง๋นต ์ฝœ)
export default async function WeatherBoard() {
  const dbData = await db.query("SELECT * FROM weather"); // DB ์ง์ ‘ ์ฐŒ๋ฅด๊ธฐ!
  const htmlResult = HeavyMarkdownToHtml(dbData.content);
 
  // ๐Ÿ’ฅ ๋ฏธ์นœ ํ˜œํƒ: ์œ„์—์„œ ์“ฐ์ธ HeavyMarkdownToHtml ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์†Œ์Šค์ฝ”๋“œ๋Š”
  // ์œ ์ €์˜ ๋ธŒ๋ผ์šฐ์ €๋กœ 1kb๋„ ์ „์†ก(๋‹ค์šด๋กœ๋“œ)๋˜์ง€ ์•Š๋Š”๋‹ค! ์˜ค์ง ๋ณ€ํ™˜๋œ <div> ๊ฒฐ๊ณผ๋ฌผ๋งŒ ์ „์†ก!
  return <div>{htmlResult}</div>;
}

์ด๊ฑด ๊ธฐ์กด CSR ๋ฆฌ์•กํŠธ๋กœ์„  ๊ฐํžˆ ์ƒ์ƒ๋„ ๋ชปํ•  ์••๋„์ ์ธ ๋Šฅ๋ ฅ์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ ํฌ๊ธฐ ์ œ๋กœ, ๋กœ๋”ฉ ์ œ๋กœ.

โœ… 2. use client ์„ ์–ธ์˜ ์ง„์งœ ๋œป (๋„๊ฐœ๊ต ๋‚ด๋ฆฌ๊ธฐ)

๊ทธ๋Ÿฐ๋ฐ ์œ„ ๊ฒŒ์‹œํŒ ์•ˆ์— "๐Ÿ‘ ์ข‹์•„์š” ๋ฒ„ํŠผ"์„ ๋‹ฌ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํด๋ฆญํ•˜๋ฉด ์ˆซ์ž๊ฐ€ ์˜ฌ๋ผ๊ฐ€๋Š” ์ƒํƒœ(useState)๊ฐ€ ํ•„์š”ํ•˜์ฃ .
์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ export default function WeatherBoard ์•ˆ์— onClick= ์ด๋”ด ๊ฑธ ์“ฐ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋นก! ํ„ฐ์ง‘๋‹ˆ๋‹ค.

"Error: Event handlers cannot be passed to Client Component props. (์ด๋ด! ์—ฌ๊ธด ์„œ๋ฒ„ ์ฃผ๋ฐฉ์ด๋ผ๊ณ ! ์œ ์ € ๋งˆ์šฐ์Šค ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋‚ด๊ฐ€ ์—ฌ๊ธฐ์„œ ์–ด๋–ป๊ฒŒ ๊ฐ์ง€ํ•ด!)"

์ด๋Ÿด ๋•Œ ์“ฐ๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ use client ์ž…๋‹ˆ๋‹ค.
use client๋Š” "๋ฆฌ์•กํŠธ ์—”์ง„๋‹˜, ์š” ํŒŒ์ผ๋ถ€ํ„ฐ๋Š” ์ฃผ๋ฐฉ(์„œ๋ฒ„) ๋ฐ–์œผ๋กœ ๋˜์ ธ์„œ, ์œ ์ € ํฐ(ํด๋ผ์ด์–ธํŠธ) ์•ˆ์—์„œ ์ง์ ‘ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์‹คํ–‰๋˜๊ฒŒ ๋ฒˆ๋“ค์„ ํฌ์žฅ ๋ฐฐ๋‹ฌํ•ด์ฃผ์„ธ์š”!" ๋ผ๋Š” ๋„คํŠธ์›Œํฌ ๊ฒฝ๊ณ„์„ (Boundary) ์ปคํŒ… ์ง€์‹œ์–ด ์ž…๋‹ˆ๋‹ค.

// ๐ŸŽฏ 1. LikeButton.tsx ํŒŒ์ผ (์ƒˆ๋กœ ๋ถ„๋ฆฌ)
'use client' // ์—ฌ๊ถŒ์„ ๋ฐœ๊ธ‰ํ–ˆ๋‹ค. "๋‚˜๋Š” ์ง€๊ธˆ๋ถ€ํ„ฐ ๋ธŒ๋ผ์šฐ์ € ํด๋ผ์ด์–ธํŠธ ๋•…์œผ๋กœ ์ž…๊ตญํ•  ์ฝ”๋“œ๋‹ค."
 
import { useState } from 'react';
 
export default function LikeButton() {
  const [likes, setLikes] = useState(0); // ํฐ์—์„œ ๋Œ์•„๊ฐˆ ๋กœ์ง
  return <button onClick={() => setLikes(c => c+1)}>โค๏ธ {likes}</button>;
}

์ด์ œ ์„œ๋ฒ„์—์„œ ๋„๋Š” ๊ฑฐ๋Œ€ํ•œ ๊ฒŒ์‹œํŒ(WeatherBoard) ์•ˆ์—, ํด๋ผ์ด์–ธํŠธ์—์„œ ์ƒํ˜ธ์ž‘์šฉํ•  ์ž‘์€ ์กฐ๊ฐ(LikeButton)์„ ๊ตฌ๋ฉ ์†ก์†ก ํŒŒ์„œ ๋ผ์›Œ ๋„ฃ์œผ๋ฉด ํ™˜์ƒ์ ์ธ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์™„์„ฑ๋ฉ๋‹ˆ๋‹ค.

// ๐ŸŽฏ 2. WeatherBoard.tsx ํŒŒ์ผ (์„œ๋ฒ„ ์ฃผ๋ฐฉ)
// (use client ๊ตฌ๋ฌธ ์—†์Œ. ๊ณ ๋กœ ์„œ๋ฒ„)
import LikeButton from './LikeButton'; // ๋ธŒ๋ฆฟ์ง€ ๊ฒฐํ•ฉ!
 
export default async function WeatherBoard() {
  return (
    <div>
      <h1>์˜ค๋Š˜์˜ ๋‚ ์”จ (์„œ๋ฒ„์—์„œ DB ๊ธ์–ด์˜ด)</h1>
      <p>๊ตฌ๋ฆ„ ๋งŽ์Œ</p>
      
      {/* ๐Ÿš€ ์—ฌ๊ธฐ ํ•˜์œ„๋ถ€ํ„ฐ๋Š” ํด๋ผ์ด์–ธํŠธ ํฐ์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋Œ๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค ๐Ÿš€ */}
      <LikeButton />
    </div>
  );
}

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ "๋‚˜๋ญ‡์žŽ(Leaf) ๋๋‹จ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ชฐ์•„๋‚ด๋ผ (Push client components to the leaves)" ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.
๋ฌด๊ฑฐ์šด ๋ Œ๋”๋ง ํŠธ๋ฆฌ์˜ ๊ธฐ๋‘ฅ๊ณผ ๊ฐ€์ง€(Layout, Data Fetching, Markdown ๋ Œ๋”)๋Š” ํŠผํŠผํ•œ ์„œ๋ฒ„์—์„œ ๋งก์•„ ๋‹ค ๊ทธ๋ ค๋ฒ„๋ฆฌ๊ณ , ๋‚˜๋ญ‡์žŽ ๋์—์„œ ์‚ด๋ž‘๊ฑฐ๋ฆฌ๋Š” ๋ฒ„ํŠผ ์ธํ„ฐ๋ž™์…˜ ๋ถ€์Šค๋Ÿฌ๊ธฐ๋“ค๋งŒ ๋–ผ์–ด๋‚ด์„œ ์œ ์ € ๋ธŒ๋ผ์šฐ์ €(ํฐ)์— ์ „์†กํ•˜๋Š” ํ™˜์ƒ์ ์ธ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ตฌ์กฐ.

์ด๊ฒƒ์ด ํ”„๋ก ํŠธ์—”๋“œ์˜ ๋‹ค์Œ ๋ชฉ์ ์ง€, ๋ธŒ๋ฆฟ์ง€ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ํŒจํ„ด ์ž…๋‹ˆ๋‹ค.


๐Ÿ ๋“œ๋””์–ด, ๋Œ€๋‹จ์› ์ด์ •๋ฆฌ

์ง€๊ธˆ๊นŒ์ง€ ์‹ ์ž… '์˜์ฒ '์ด๊ฐ€ ๊ฒช์€ ๋ชจ๋“  ๋ฆฌ์•กํŠธ์˜ ํ•จ์ •๊ณผ, ๋ฆฌ๋“œ '์˜ํ˜ธ'๊ฐ€ ์•Œ๋ ค์ค€ ์‹œ๋‹ˆ์–ด์˜ ํ†ต์ œ ๊ธฐ์ˆ ์„ ๋ชฉ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. ์ƒํƒœ ๊ด€๋ฆฌ์˜ ์ฐฉ๊ฐ (๊ฐ€์ด๋“œ 1~4): ์ƒํƒœ๋Š” ๋ Œ๋”๋ง ์Šค๋ƒ…์ƒท์ด๋‹ค. ๋ถˆ๋ณ€์„ฑ์€ ํ™”๋ฉด์„ ์ƒˆ๋กœ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•œ ์‹ ํ˜ธํƒ„์ด๋‹ค. ํ•จ๋ถ€๋กœ ์ „์—ญ ๋„๊ตฌ๋ฅผ ์น˜๋•์น˜๋• ๋ฐ”๋ฅด๊ธฐ ์ „์— "State Colocation(๋ฐ‘๋™์œผ๋กœ ๋ฐ€์–ด๋‚ด๊ธฐ)"์„ ์‹ค์ฒœํ•˜๋ผ.
  2. ์ดํŽ™ํŠธ์™€ ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฏธ๋“œ (๊ฐ€์ด๋“œ 5~8): useEffect๋Š” ๋งˆ์šดํŠธ ์‹œ ์ฝœ๋ฐฑ ์˜๋Š” ์“ฐ๋ ˆ๊ธฐํ†ต์ด ์•„๋‹ˆ๋ผ, ๋ฆฌ์•กํŠธ ์™ธ๋ถ€ ์˜์—ญ(DOM API, ์„œ๋ฒ„ ๋™๊ธฐํ™”)๊ณผ ์ˆ˜์œ„๋ฅผ ๋งž์ถ”๋Š” ๋™๊ธฐํ™” ํ•˜์ˆ˜๊ตฌ๋‹ค.
  3. ์ตœ์ ํ™” ๊ฐ•๋ฐ•์˜ ํ•ด์ฒด (๊ฐ€์ด๋“œ 9~11): useMemo๋‚˜ useCallback์œผ๋กœ ๋ง‰์žฅ ๋ฐฉ์–ด๋ฅผ ์งœ๊ธฐ ์ „์—, "์ปดํฌ๋„ŒํŠธ ์ชผ๊ฐœ๊ธฐ + Children ํ•ฉ์„ฑ + Context State/Action ๋ถ„๋‹จ" ์ด๋ผ๋Š” ์˜ํ˜ธ์˜ ๊ทผ์›์  ์•„ํ‚คํ…์ฒ˜ ์ˆ˜์ˆ ๋ฒ•์„ ๋“ค์ด๋ฐ€์–ด๋ผ.
  4. ์ฐจ์„ธ๋Œ€ ๋””์ž์ธ ์บก์Аํ™” (๊ฐ€์ด๋“œ 12~14): ์ œ์–ด๊ถŒ์„ ๋ถ€๋ชจ๋กœ ๋‹ค ๋‚ด๋˜์ง€๊ณ (IoC), ์ปดํŒŒ์šด๋“œ ๋ธ”๋ก์„ ์ฐข์–ด ๋ฐœ๊ธฐ๋ฉฐ, ๋‡Œ์ˆ˜์ˆ (Headless Hook)๋กœ ๋กœ์ง ์ฝ”์–ด๋ฅผ ์™„๋ฒฝํžˆ ์ ์ถœํ•˜๋ฉด ๊ทธ ์–ด๋–ค ๋””์ž์ธ์ด ๋ฐ”๋€Œ์–ด๋„ ๋‘๋ ต์ง€ ์•Š๋‹ค.
  5. ์„œ๋ฒ„๋กœ ๊ท€ํ™˜ (ํ˜„์žฌ ๊ฐ€์ด๋“œ 15): ์ด์ œ ๋ฆฌ์•กํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €๋ผ๋Š” ๊ฐ์˜ฅ์„ ํƒˆ์ถœํ•ด ์„œ๋ฒ„๊นŒ์ง€ ์ง‘์–ด์‚ผ์ผฐ๋‹ค. ์˜ํ˜ธ์™€ ์˜์ฒ ์ด๋Š” ๋ฐ”์•ผํ๋กœ RSC ๋ผ๋Š” ์ƒˆ๋กœ์šด ๋Œ€๋ฅ™์— ๋„๋‹ฌํ–ˆ๋‹ค.

๋‹จ์–ธ์ปจ๋Œ€, ๋‹น์‹ ์ด 15๊ฐ•๊นŒ์ง€์˜ ์ฝ”๋“œ๋ฅผ ๋ˆˆ์œผ๋กœ ์ข‡์œผ๋ฉฐ ๊ณ ๊ฐœ๋ฅผ ๋„๋•์˜€๋‹ค๋ฉด, ๋‹น์‹ ์€ ์ด๋ฏธ ๋‹จ์ˆœํ•œ '์ฝ”๋”'๋ฅผ ๋„˜์–ด ์‹œ์Šคํ…œ์˜ ๋ณ‘๋ชฉ์„ ์ง„๋‹จํ•˜๊ณ  ๋ถ€์ˆด๋ฒ„๋ฆฌ๋Š” '5๋…„ ์ฐจ ํ”„๋ก ํŠธ์—”๋“œ ์„ค๊ณ„์ž'์˜ ๋‡Œ๋ฅผ ์žฅ์ฐฉํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋™์•ˆ ๊ธฐ๋‚˜๊ธด ๋Œ€์žฅ์ •์„ ํ•จ๊ป˜ํ•œ ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ ์ „๋Œ€์›์—๊ฒŒ ๋ฐ•์ˆ˜๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค! ์ฝ”๋”ฉ์˜ ์ถ•๋ณต์ด ๋‹น์‹ ์˜ ๋นŒ๋“œ ํŒŒ์ดํ”„๋ผ์ธ๊ณผ ํ•จ๊ป˜ํ•˜๊ธฐ๋ฅผ.


๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

15๊ฐ• ๋Œ€์žฅ์ •์„ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ ๋‚ด ๋จธ๋ฆฌํ†ต์„ ๋ฒˆ๊ฐœ์ฒ˜๋Ÿผ ๋•Œ๋ฆฐ ๊นจ๋‹ฌ์Œ ํ•˜๋‚˜. use client๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ '์„œ๋ฒ„ ์ฃผ๋ฐฉ์—์„œ ์œ ์ € ๋ชจ๋ฐ”์ผ ํฐ์œผ๋กœ ๊ตฝ๊ธฐ๋ฅผ ๋– ๋„˜๊ธฐ๋Š”' ์ผ์ข…์˜ ๋ฌด๊ฑฐ์šด ๋„๊ฐœ๊ต ์ง€์‹œ์–ด์˜€๋‹ค๋‹ˆ! ๋ฌด์กฐ๊ฑด ์ตœ์ƒ๋‹จ์— ์ ๊ณ  ๋ณด๋ ค๊ณ  ํ–ˆ๋˜ ๋ฌด์ง€ํ•จ์ด ๋ถ€๋„๋Ÿฝ๋‹ค.

๐Ÿ’ก "๋ฌด๊ฑฐ์šด ๋ผˆ๋Œ€์™€ ๋งˆํฌ๋‹ค์šด ๊ทธ๋ฆฌ๊ธฐ ์ž‘์—…์€ ์„œ๋ฒ„์—์„œ ์‹น ๋๋‚ด๊ณ  ์˜ค๋ผ. ์˜ค์ง ๋น™๊ธ€๋น™๊ธ€ ๋„๋Š” ์ž์ž˜ํ•œ ๋ฒ„ํŠผ ๋‚˜๋ญ‡์žŽ(Leaf)๋“ค์—์„œ๋งŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ํƒœ์›Œ๋ผ(ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธํ™”). ์ด๊ฒƒ์ด RSC์˜ ๊ถ๊ทน์  ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์ง„๋ฆฌ๋‹ค."

์ง„์งœ ์ด ํ”„๋ก ํŠธ์—”๋“œ ์„ค๊ณ„ ๋Œ€๋ฅ™์˜ 1๋ถ€ํ„ฐ ๋๊นŒ์ง€ ์˜ํ˜ธ ๋‹˜์—๊ฒŒ ์ฐธ๊ต์œก ๋‹นํ•œ ๊ธฐ๋ถ„์ด๋‹ค. ๋” ์ด์ƒ useEffect ๋Šช์— ๋น ์ ธ ํ—ˆ์šฐ์ ๋Œ€๊ฑฐ๋‚˜ ๋ฌด์ง€์„ฑ useMemo๋ฅผ ๋ฐ”๋ฅด๋Š” ์ข€๋น„ ๊ฐœ๋ฐœ์ž๋กœ๋Š” ์‚ด์ง€ ์•Š์„ ๊ฑฐ๋‹ค. ๊ทธ์ € ๊ฐ์‚ฌํ•˜๊ณ , ๋„ˆ๋ฌด ํ›„๋ จํ•˜๋‹ค!


๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ(์—ํ•„๋กœ๊ทธ) ํ€ด์ฆˆ

Q1. ๋‹น์‹ ์ด Next.js App Router ํ™˜๊ฒฝ์—์„œ <Layout /> ํŽ˜์ด์ง€๋ฅผ ์ž‘์—… ์ค‘์ž…๋‹ˆ๋‹ค. ์œ ์ €์—๊ฒŒ ๊ฑฐ๋Œ€ํ•œ 3D ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์บ˜๋ฆฐ๋” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ต์งธ๋กœ ๋‹ค์šด๋กœ๋“œ์‹œํ‚ค๋ฉฐ ๋ชจ๋ฐ”์ผ ํฐ์„ ๋ถˆํƒ€๊ฒŒ ๋งŒ๋“œ๋Š” '์•…๋• ๊ฐœ๋ฐœ์ž'์‹ ์ตœ์•…์˜ ์„ค๊ณ„๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

  • A) async function Layout() {}
  • B) ์ตœ์ƒ๋‹จ์— 'use client';๋ฅผ ์ ๊ณ  ๊ทธ ๋‚ด๋ถ€์—์„œ ๋ชจ๋“  ๋ฌด๊ฑฐ์šด 3D ์ปดํฌ๋„ŒํŠธ๋“ค์„ import ํ•˜์—ฌ ๊ฑฐ๋Œ€ํ•œ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ธฐ์›Œ ์˜ฌ๋ฆฌ๋Š” ์ง“.
  • C) import { Suspense } from 'react'

โœ… ์ •๋‹ต: B

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: RSC ์„ธ๊ณ„๊ด€์—์„œ 'use client' ์ง€์‹œ์–ด์˜ ํŒŒ๊ธ‰๋ ฅ์ž…๋‹ˆ๋‹ค. ์ด ์ง€์‹œ์–ด๋ฅผ ๋‹จํŒŒ์žฅ ํญํƒ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์„ธ์š”. ์ตœ์ƒ๋‹จ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์— ์ด ์ง€์‹œ์–ด๋ฅผ ์ ์–ด๋ฒ„๋ฆฌ๋ฉด, ๊ทธ ํŒŒ์ผ ๋‚ด์—์„œ Import๋˜์–ด ๋ฌผ๋ ค ๋“ค์–ด์˜จ "์ž์‹์˜ ์ž์‹์˜ ๋ชจ๋“  ํ•˜์œ„ ํŠธ๋ฆฌ๋“ค" ๊นŒ์ง€ ๊ฐ•์ œ๋กœ ๋ชฝ๋•… ๋ธŒ๋ผ์šฐ์ €(ํด๋ผ์ด์–ธํŠธ)๊ฐ€ ๋‹ค์šด๋กœ๋“œํ•ด์•ผ ํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฒˆ๋“ค ์˜ฅํ† ๋กœ ์ถ”๋ฐฉ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์˜์ฒ ์ด์˜ "๊ท€์ฐฎ์œผ๋‹ˆ๊นŒ ์ตœ์ƒ๋‹จ์— ๋”ฑ ํ•œ ๋ฒˆ๋งŒ use client ์“ฐ๋ฉด ๋˜์ฃ ?" ๊ผผ์ˆ˜๋Š” ๊ฒฐ๊ตญ ๊ณผ๊ฑฐ์˜ CSR ๋ฒˆ๋“ค ์ง€์˜ฅ ์‚ฌ์ด์ฆˆ(์ˆ˜์‹ญ ๋ฉ”๊ฐ€)๋กœ ํšŒ๊ท€ํ•˜๋Š” ํŒŒ๋ฉธ์  ๊ฒฐ๊ณผ๋ฅผ ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ์ƒ๋‹จ ๋ผˆ๋Œ€๋Š” ์„œ๋ฒ„(RSC)๋กœ ์œ ์ง€ํ•˜๊ณ  ๋„ํŠธ๋จธ๋ฆฌ ์ž”๊ฐ€์ง€ ๋ฒ„ํŠผ๋“ค๋งŒ ๋ถ„๋ฆฌํ•ด์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ฐ€์–ด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Q2. ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ(RSC) ๋‚ด๋ถ€์—์„œ ์ ˆ๋Œ€๋กœ, ์ฃฝ์—ˆ๋‹ค ๊นจ์–ด๋‚˜๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” React ์ƒํƒœ๊ณ„์˜ ์š”์†Œ๋“ค์€ ์–ด๋–ค ๊ฒƒ๋“ค์ธ๊ฐ€์š”?

  • A) <form action="...">
  • B) ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ์˜ console.log("๋ Œ๋”๋จ!")
  • C) useState, useEffect, useContext, ๊ทธ๋ฆฌ๊ณ  onClick, onChange ๊ฐ™์€ ๋ชจ๋“  ์œ ์ € ์ƒํ˜ธ์ž‘์šฉ ๋ธŒ๋ผ์šฐ์ € DOM ์ด๋ฒคํŠธ.

โœ… ์ •๋‹ต: C

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ์„œ๋ฒ„ ๋ Œ๋”๋ง ์ฃผ๋ฐฉ์€ "์ƒ์„ฑ๋œ ํ›„ ํ•œ ๋ฒˆ ์™„๋ฒฝํžˆ ์ •์ง€๋œ HTML ๋ฌธ์ž์—ด ์•ก์ž ์‚ฌ์ง„" ๋งŒ ๋”ธ๋ž‘ ํฐ์œผ๋กœ ์ด์ค€๋‹ค๊ณ  ํ–ˆ์ฃ ? ์ € ๋จธ๋‚˜๋จผ ์บ˜๋ฆฌํฌ๋‹ˆ์•„ ๋ฐ์ดํ„ฐ ์„ผํ„ฐ ์ฃผ๋ฐฉ์— ์žˆ๋Š” ์„œ๋ฒ„ CPU๊ฐ€ ์œ ์ €์˜ ๋ฐฉ๊ตฌ์„ ๋ชจ๋ฐ”์ผ ํฐ ์•ก์ •์„ ์†๊ฐ€๋ฝ์œผ๋กœ ๋ˆ„๋ฅด๋Š” onClick์„ ์›๊ฒฉ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์„ ๋ฆฌ๊ฐ€ ๋งŒ๋ฌดํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒํƒœ ๋ณ€ํ™”(State) ์กฐ์ž‘์ด๋‚˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ชจ๋“  ํ›…์Šค, ์ฐฝ๋ฌธ ํฌ๊ธฐ๋ฅผ ์Ÿค๋Š” window.innerWidth ๋”ฐ์œ„๋ฅผ ์ผ์ ˆ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋Š” ์ฒ ์ €ํžˆ ๊ณ ๋ฆฝ๋œ ๋ฐฑ์—”๋“œ(Backend) ๊ณต๊ฐ„์ž…๋‹ˆ๋‹ค. ์˜ค์ง ๋ฐ์ดํ„ฐ(DB ์ฟผ๋ฆฌ)๋ฅผ ๋Œ์–ด๋‹ค ์‹œ๊ฐํ™” ๊ป๋ฐ๊ธฐ(HTML)๋กœ ๋ฎ์–ด ์”Œ์šฐ๋Š” ์••๋„์  ์ปดํŒŒ์ผ ํž˜๊ณผ ์†๋„๋งŒ ๊ฐ€์งˆ ๋ฟ์ด์ฃ .

[THE END] ๋‹น์‹ ์€ ๋ชจ๋“  ๊ณผ์ •์„ ์ด์ˆ˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ํ˜„์—…์œผ๋กœ ๋‚˜์•„๊ฐ€, ๋ถˆํ•„์š”ํ•œ useEffect์™€ useMemo๋ฅผ ์‚ฌ๋ƒฅํ•˜์‹ญ์‹œ์˜ค!