๐ก 15. ์๋ฒ๋ก ํ๊ทํ๋ค: RSC์ next.js ๋ธ๋ฆฟ์ง
๐ ๊ฐ์
React ์ํ๊ณ์ ํจ๋ฌ๋ค์ ๋ณํ์ธ ์๋ฒ ์ปดํฌ๋ํธ(RSC)์ ์๋ฏธ์, use client ์ง์์ด๊ฐ ํด๋ผ์ด์ธํธ์ ์๋ฒ๋ฅผ ๋๋๋ ๊ฒฝ๊ณ์ (Boundary) ์ญํ ์ ์ด๋ป๊ฒ ์ํํ๋์ง ์ด์ ๋ฆฌํฉ๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- React Server Components(RSC)๊ฐ ๊ธฐ์กด์ SSR(Server-Side Rendering)๊ณผ ์์ ํ ๋ค๋ฅธ ๋ง๋ฒ์ด๋ผ๋ ์ ์ ์ดํดํ๋ค.
use client์ต์๋จ ์ง์์ด์ ์ง์ง ์๋ฏธ๊ฐ '๋ธ๋ผ์ฐ์ ์ ์ฉ ์คํ'์ด ์๋๋ผ ๋จ์ ์ ๊ฒฝ๊ณ์ (Network Boundary) ์์ ์๋ฒฝํ ๊ทธ๋ ค๋ผ ์ ์๋ค.- ์ปดํฌ๋ํธ์ ์ฑ ์ ์์ฌ์ง(์๋ฒ๋, ํด๋ผ์ด์ธํธ๋)๋ฅผ ๋ช ํํ ํ๋ณํ๋ ์๊ฐ์ ๊ฐ๋๋ค. (๋๋จ์ ๋ง๋ฌด๋ฆฌ)
๐ ๋ชฉ์ฐจ
- ๐ค ์ ์์์ผ ํ๋๊ฐ:
JS ๋ฒ๋ค๋ค์ด์ดํธ์ ์ ์ - ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ๊ทน์ ์ฒด๋: RSC์
use client์ ์ง์ง ์๋ฌด - ๐ ๋๋์ด, ๋๋จ์ ์ด์ ๋ฆฌ
- ๐ ๋ง๋ฌด๋ฆฌ(์ํ๋ก๊ทธ) ํด์ฆ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 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์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
๊ณผ๊ฑฐ (Client Component ์์ฃผ ์๋):
์๋น ์๋ฆฌ์ฌ(์์ฒ )๊ฐ ์๋(๋ธ๋ผ์ฐ์ )์๊ฒ ์๊ณ ๊ธฐ, ์ผ์ฑ, ์นผ, ๋๋ง, ๊ฐ์ค๋ฒ๋(๊ฑฐ๋ํ JS ๋ฒ๋ค ์ฝ๋ ๋ฉ์ด๋ฆฌ)๋ฅผ ๋ฐ์ค ์ฑ๋ก ํ ์ด๋ธ์ ๋ค์ง๊ณ ์ง ๋์ ธ์ค.
โ์๋! ์ฌ๊ธฐ์๋ถํฐ๋ ์๋ ํด๋ํฐ์ด ์ง์ ๊ฐ์ค๋ฒ๋ ์ผ๊ณ (useEffect), ๋ค์ด๋ฒ์ ๋ ์จ ๋ฌผ์ด๋ณด๊ณ (fetch), ๊ณ ๊ธฐ ๊ตฌ์์ ํ๋ฒ๊ฑฐ ์กฐ๋ฆฝ(๋ ๋๋ง)ํด ๋์ธ์!โ -> ์ ์ ํฐ์ด ์์ฒญ ๋จ๊ฑฐ์์ง๊ณ ๋ก๋ฉ์ด ๊น.ํ์ฌ (์๋ฒ ์ปดํฌ๋ํธ, 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~4): ์ํ๋ ๋ ๋๋ง ์ค๋ ์ท์ด๋ค. ๋ถ๋ณ์ฑ์ ํ๋ฉด์ ์๋ก ๊ทธ๋ฆฌ๊ธฐ ์ํ ์ ํธํ์ด๋ค. ํจ๋ถ๋ก ์ ์ญ ๋๊ตฌ๋ฅผ ์น๋์น๋ ๋ฐ๋ฅด๊ธฐ ์ ์ "State Colocation(๋ฐ๋์ผ๋ก ๋ฐ์ด๋ด๊ธฐ)"์ ์ค์ฒํ๋ผ.
- ์ดํํธ์ ๋ผ์ดํ์ฌ์ดํด ๋ฏธ๋ (๊ฐ์ด๋ 5~8):
useEffect๋ ๋ง์ดํธ ์ ์ฝ๋ฐฑ ์๋ ์ฐ๋ ๊ธฐํต์ด ์๋๋ผ, ๋ฆฌ์กํธ ์ธ๋ถ ์์ญ(DOM API, ์๋ฒ ๋๊ธฐํ)๊ณผ ์์๋ฅผ ๋ง์ถ๋ ๋๊ธฐํ ํ์๊ตฌ๋ค. - ์ต์ ํ ๊ฐ๋ฐ์ ํด์ฒด (๊ฐ์ด๋ 9~11):
useMemo๋useCallback์ผ๋ก ๋ง์ฅ ๋ฐฉ์ด๋ฅผ ์ง๊ธฐ ์ ์, "์ปดํฌ๋ํธ ์ชผ๊ฐ๊ธฐ + Children ํฉ์ฑ + Context State/Action ๋ถ๋จ" ์ด๋ผ๋ ์ํธ์ ๊ทผ์์ ์ํคํ ์ฒ ์์ ๋ฒ์ ๋ค์ด๋ฐ์ด๋ผ. - ์ฐจ์ธ๋ ๋์์ธ ์บก์ํ (๊ฐ์ด๋ 12~14): ์ ์ด๊ถ์ ๋ถ๋ชจ๋ก ๋ค ๋ด๋์ง๊ณ (IoC), ์ปดํ์ด๋ ๋ธ๋ก์ ์ฐข์ด ๋ฐ๊ธฐ๋ฉฐ, ๋์์ (Headless Hook)๋ก ๋ก์ง ์ฝ์ด๋ฅผ ์๋ฒฝํ ์ ์ถํ๋ฉด ๊ทธ ์ด๋ค ๋์์ธ์ด ๋ฐ๋์ด๋ ๋๋ ต์ง ์๋ค.
- ์๋ฒ๋ก ๊ทํ (ํ์ฌ ๊ฐ์ด๋ 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๋ฅผ ์ฌ๋ฅํ์ญ์์ค!