본문으둜 κ±΄λ„ˆλ›°κΈ°

🎈 Chapter 9: λ¦¬μ•‘νŠΈ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈ

RSC(React Server Component)λŠ” μ„œλ²„μ—μ„œ "μ‹€ν–‰"λ˜λŠ” μƒˆλ‘œμš΄ μ’…λ₯˜μ˜ μ»΄ν¬λ„ŒνŠΈλ‘œ, ν΄λΌμ΄μ–ΈνŠΈ μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ— ν¬ν•¨λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이 μ»΄ν¬λ„ŒνŠΈλŠ” λΉŒλ“œ μ‹œμ μ— 싀행될 수 있기 λ•Œλ¬Έμ— 파일 μ‹œμŠ€ν…œμ—μ„œ 데이터λ₯Ό μ½κ±°λ‚˜ 정적 μ½˜ν…μΈ λ₯Ό κ°€μ Έμ˜€κ±°λ‚˜ 데이터 λ ˆμ΄μ–΄μ— μ ‘κ·Όν•˜λŠ” λ“±μ˜ μž‘μ—…μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ—μ„œ 데이터λ₯Ό λΈŒλΌμš°μ € ν™˜κ²½μ— μžˆλŠ” ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈμ˜ ν”„λ‘­μœΌλ‘œ μ „λ‹¬ν•¨μœΌλ‘œμ¨ 맀우 효울적이고 μ„±λŠ₯이 λ›°μ–΄λ‚œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œλ§Œ μ‹€ν–‰λ˜λŠ” νŠΉμˆ˜ν•œ μ’…λ₯˜μ˜ μ»΄ν¬λ„ŒνŠΈλ₯Ό μΌμ»«μŠ΅λ‹ˆλ‹€. μƒˆλ‘œμš΄ ν˜•νƒœμ˜ 이 μ»΄ν¬λ„ŒνŠΈλ₯Ό 더 잘 μ΄ν•΄ν•˜λ €λ©΄ λ¨Όμ € λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈκ°€ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜μΌ λΏμ΄λΌλŠ” 사싀을 κΈ°μ–΅ν•΄μ•Ό ν•©λ‹ˆλ‹€. λͺ¨λ“  μ»΄ν¬λ„ŒνŠΈλŠ” 가상 DOM인 λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ„ λ§ˆμ°¬κ°€μ§€μž…λ‹ˆλ‹€. μ„œλ²„λ‚˜ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ‹€ν–‰λœ ComponentλŠ” 가상 DOM을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

μž₯점​

  • μš°λ¦¬κ°€ 계산 λŠ₯λ ₯을 μ œμ–΄ν•  수 μžˆλŠ” μ„œλ²„μ—μ„œλ§Œ μ‹€ν–‰λ©λ‹ˆλ‹€. μ˜ˆμΈ‘ν•˜κΈ° μ–΄λ €μš΄ ν΄λΌμ΄μ–ΈνŠΈ κΈ°κΈ°μ—μ„œ μ‹€ν–‰λ˜λŠ” 것이 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— μ„±λŠ₯을 더 잘 μ˜ˆμΈ‘ν•˜κ²Œ λ©λ‹ˆλ‹€.
  • μ•ˆμ „ν•œ μ„œλ²„ ν™˜κ²½μ—μ„œ μ‹€ν–‰λ˜λ―€λ‘œ 토큰과 같은 λ―Όκ°ν•œ 정보가 유좜될 κ±±μ • 없이 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ•ˆμ „ν•˜κ²Œ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” λΉ„λ™κΈ°λ‘œ λ™μž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ λ„€νŠΈμ›Œν¬λ₯Ό 톡해 ν΄λΌμ΄μ–ΈνŠΈλ‘œ μ „μ†‘ν•˜κΈ° 전에 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ˜ λ™μž‘μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ 기닀릴 수 μžˆμŠ΅λ‹ˆλ‹€.

μ„œλ²„ λ Œλ”λ§β€‹

기본적으둜 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ™€ μ„œλ²„ λ Œλ”λ§μ„ 두 개의 독립적인 ν”„λ‘œμ„ΈμŠ€λ‘œ 생각할 수 μžˆμŠ΅λ‹ˆλ‹€.
ν•œ ν”„λ‘œμ„ΈμŠ€λŠ” μ„œλ²„μ—μ„œ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ Œλ”λ§ν•œ ν›„ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈ 트리λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. 또 λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μΈ μ„œλ²„ λ Œλ”λŸ¬λŠ” μ΄λ ‡κ²Œ μƒμ„±λœ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈ 트리λ₯Ό λ§ˆν¬μ—…μœΌλ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€. λ³€ν™˜λœ λ§ˆν¬μ—…μ€ λ„€νŠΈμ›Œν¬λ₯Ό 톡해 ν΄λΌμ΄μ–ΈνŠΈμ— μŠ€νŠΈλ¦¬λ°λ©λ‹ˆλ‹€.

μ»΄ν¬λ„ŒνŠΈλ₯Ό λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ‘œ λ Œλ”λ§ν•˜λŠ” ν”„λ‘œμ„ΈμŠ€μ™€ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό HTML λ¬Έμžμ—΄μ΄λ‚˜ 슀트림으둜 λ Œλ”λ§ν•˜λŠ” ν”„λ‘œμ„ΈμŠ€λΌλŠ” 점을 κ³ λ €ν•˜λ©΄ 이 두 κ°œλ…μ΄ μ–΄λ–»κ²Œ ν•¨κ»˜ λ™μž‘ν•˜κ²Œ λ˜λŠ”μ§€ μ§μž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈμ˜ 트리둜 λ°”κΎΈλŠ” 첫 번째 ν”„λ‘œμ„ΈμŠ€λ₯Ό RSC λ Œλ”λŸ¬λΌκ³  ν•˜κ³ , λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό HTML 슀트림으둜 λ°”κΎΈλŠ” 두 번째 ν”„λ‘œμ„ΈμŠ€λ₯Ό μ„œλ²„ λ Œλ”λŸ¬λΌκ³  ν•˜κ² μŠ΅λ‹ˆλ‹€.

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ™€ μ„œλ²„ λ Œλ”λ§μ˜ μƒν˜Έ μž‘μš©μ„ λ‹€μŒκ³Ό 같이 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.

  1. μ„œλ²„μ—μ„œ JSX νŠΈλ¦¬λŠ” μ—˜λ¦¬λ¨ΌνŠΈ 트리둜 λ³€ν™˜ν•©λ‹ˆλ‹€.
  2. 그런 λ‹€μŒ, μ„œλ²„λŠ” 이 μ—˜λ¦¬λ¨ΌνŠΈ 트리λ₯Ό λ¬Έμžμ—΄μ΄λ‚˜ 슀트림으둜 μ§λ ¬ν™”ν•©λ‹ˆλ‹€.
  3. λ¬Έμžμ—΄λ‘œ λ³€ν™˜λœ JSON 객체가 ν΄λΌμ΄μ–ΈνŠΈλ‘œ μ „μ†‘λ©λ‹ˆλ‹€.
  4. ν΄λΌμ΄μ–ΈνŠΈ 츑의 λ¦¬μ•‘νŠΈλŠ” JSON λ¬Έμžμ—΄μ„ νŒŒμ‹±ν•΄ 읽고 ν‰μ†Œμ™€ 닀름없이 λ Œλ”λ§ν•©λ‹ˆλ‹€.

이λ₯Ό μ„œλ²„ μ½”λ“œλ‘œ μ„€λͺ…ν•˜λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

// server.js
const express = require("express");
const path = require("path");
const react = require("react");
const ReactDOMServer = require("react-dom/server");
const App = require("./src/App");

const app = express();

app.use(express.static(path.join(__dirname, "build")));

app.get("*", (req, res) => {
// 비법 μ†ŒμŠ€ λΆ€λΆ„
const rscTree = await turnServerComponentsIntoTreeOfElements(<App />);
// 비법 μ†ŒμŠ€ λΆ€λΆ„ 끝

// λΉ„λ™κΈ°λ‘œ λ™μž‘ν•œ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ¬Έμžμ—΄λ‘œ λ Œλ”λ§
const html = ReactDOMServer.renderToString(rscTree);

// 전솑
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>μ˜ˆμ‹œ λ¦¬μ•‘νŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜</title>
</head>
<body>
<div id="root">${html}</div>
<script src="/static/js/main.js"></script>
</body>
</html>
`);
});

app.listen(3000, () => {
console.log("Server listening on port 3000");
})

λ…Όλ¦¬μ μœΌλ‘œ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ™€ μ„œλ²„ λ Œλ”λ§μ€ μ„œλ‘œ 보완적인 ν”„λ‘œμ„ΈμŠ€μ΄λ―€λ‘œ ꡉμž₯히 잘 μ–΄μšΈλ¦½λ‹ˆλ‹€.

λ‚΄λΆ€ ꡬ쑰​

turnServerComponentsIntoTreeOfElementsλŠ” λ¦¬μ•‘νŠΈ λ Œλ”λŸ¬μ˜ ν•œ μ’…λ₯˜μž…λ‹ˆλ‹€. <App />κ³Ό 같은 μƒμœ„ λ‹¨κ³„μ—μ„œ μ‹œμž‘ν•΄ μž¬κ·€μ μœΌλ‘œ μ»΄ν¬λ„ŒνŠΈλ₯Ό ν˜ΈμΆœν•˜κ³ , μ—¬κΈ°μ„œ λ°˜ν™˜λ˜λŠ” λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈ(즉, μžλ°”μŠ€ν¬λ¦½νŠΈ 객체)λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈκ°€ μžˆλ‹€κ³  κ°€μ •ν•΄ λ΄…μ‹œλ‹€.

<div>μ•ˆλ…•!</div>

이 μ—˜λ¦¬λ¨ΌνŠΈμ˜ μžμ‹μΈ "μ•ˆλ…•!"은 λ¬Έμžμ—΄μΌ λΏμž…λ‹ˆλ‹€. 이 λ¬Έμžμ—΄μ„ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈ λ Œλ”λŸ¬μ— μ „λ‹¬ν•˜λ©΄ λ¬Έμžμ—΄μ„ κ·ΈλŒ€λ‘œ λ°˜ν™˜ν•©λ‹ˆλ‹€. 이 λ™μž‘μ˜ 핡심은 ν΄λΌμ΄μ–ΈνŠΈμ— μžˆλŠ” λ¦¬μ•‘νŠΈμ™€ μ„œλ²„μ— μžˆλŠ” λ¦¬μ•‘νŠΈκ°€ λͺ¨λ‘ 이해할 수 μžˆλŠ” 데이터λ₯Ό λ°˜ν™˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λ¦¬μ•‘νŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„μ—μ„œ λͺ¨λ‘ λ¬Έμžμ—΄, 숫자, λΆˆλ¦¬μ–Έ 값을 μ΄ν•΄ν•˜κ³  λ Œλ”λ§ν•  수 μžˆμœΌλ―€λ‘œ λ¬Έμžμ—΄μ€ κ·ΈλŒ€λ‘œ 두어도 λ©λ‹ˆλ‹€.

배열이 μ „λ‹¬λœλ‹€λ©΄ λ°°μ—΄μ˜ map을 μ‹€ν–‰ν•˜κ³  ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•΄ μž¬κ·€μ μœΌλ‘œ λ°°μ—΄μ˜ 각 μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€. 배열은 λ‹€μŒκ³Ό 같이 μ—¬λŸ¬ 개의 μžμ‹ μ—˜λ¦¬λ¨ΌνŠΈλ‘œ ꡬ성될 수 μžˆμŠ΅λ‹ˆλ‹€.

[
<div>hi</div>,
<h1>hello</h1>,
<span>love u</span>,
(prop) => <p id={props.id}>lorem ipsum</p>,
];

λ‹€μŒμ€ 객체λ₯Ό μ²˜λ¦¬ν•˜λŠ” λ‹¨κ³„μž…λ‹ˆλ‹€. λͺ¨λ“  λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” κ°μ²΄μ§€λ§Œ, λͺ¨λ“  객체가 λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” μ•„λ‹™λ‹ˆλ‹€. λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” $$typeOf 속성을 μ§€λ‹ˆλ©°, μ†μ„±μ˜ 값은 Symbol.for('react.element')μž…λ‹ˆλ‹€. λ”°λΌμ„œ 이 속성과 μ†μ„±μ˜ 값이 μΌμΉ˜ν•˜λŠ”μ§€ ν™•μΈν•˜κ³ , 이λ₯Ό λ§Œμ‘±ν•œλ‹€λ©΄ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ‘œ μ·¨κΈ‰ν•©λ‹ˆλ‹€.
λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” string, function 두가지 νƒ€μž…μœΌλ‘œ ν‘œν˜„λ©λ‹ˆλ‹€. "div", "span" λ“±μ˜ λ‚΄μž₯ DOM μ—˜λ¦¬λ¨ΌνŠΈμ—λŠ” λ¬Έμžμ—΄μ΄ μ‚¬μš©λ˜κ³ , μ‚¬μš©μžκ°€ μž‘μ„±ν•œ <Footer />와 같은 μ»΄ν¬λ„ŒνŠΈμ—λŠ” ν•¨μˆ˜κ°€ μ‚¬μš©λ©λ‹ˆλ‹€.

λ¬Έμžμ—΄ νƒ€μž…μ΄λΌλ©΄, λ‚΄μž₯된 DOM μ—˜λ¦¬λ¨ΌνŠΈμ΄κΈ° λ•Œλ¬Έμ— κ·ΈλŒ€λ‘œ λ°˜ν™˜ν•©λ‹ˆλ‹€. λ‹€λ§Œ, μžμ‹μœΌλ‘œ λ™μ‹œμ„± λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈκ°€ 포함될 μˆ˜λ„ μžˆμœΌλ―€λ‘œ μž¬κ·€μ μœΌλ‘œ 프둭에 λŒ€ν•΄ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄ μ²˜λ¦¬ν•©λ‹ˆλ‹€.
ν•¨μˆ˜ νƒ€μž…μ΄λΌλ©΄, μ‚¬μš©μžκ°€ μž‘μ„±ν•œ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ‚˜νƒ€λ‚΄λŠ” κ²ƒμ΄λ―€λ‘œ ν•΄λ‹Ή μ»΄ν¬λ„ŒνŠΈλ₯Ό ν”„λ‘­κ³Ό ν•¨κ»˜ ν˜ΈμΆœν•˜κ³ , μ»΄ν¬λ„ŒνŠΈκ°€ λ°˜ν™˜ν•˜λŠ” JSX에 λŒ€ν•΄ μž¬κ·€μ μœΌλ‘œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€. ν•¨μˆ˜ νƒ€μž…μ˜ μ»΄ν¬λ„ŒνŠΈλ₯Ό ν˜ΈμΆœν•˜λŠ” 뢀뢄을 보면 μ•žμ— await ν‚€μ›Œλ“œκ°€ μžˆμŠ΅λ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμ— ν•¨μˆ˜ μ»΄ν¬λ„ŒνŠΈμ˜ 비동기 μž‘μ—…μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ 기닀릴 수 있고, 이λ₯Ό μœ„ν•΄ awaitλ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. μ„œλ²„μ—μ„œ await와 ν•¨κ»˜ 호좜된 μ»΄ν¬λ„ŒνŠΈλŠ” λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ°˜ν™˜ν•˜λŠ”λ°, 이λ₯Ό renderToStringμ΄λ‚˜ renderToPipeableStream에 μ „λ‹¬ν•˜λ©΄ λ¬Έμžμ—΄μ΄λ‚˜ λ¬Έμžμ—΄ 슀트림으둜 λ Œλ”λ§ν•  수 μžˆμŠ΅λ‹ˆλ‹€. κ·Έ κ²°κ³Ό, μ„œλ²„μ—μ„œ λͺ¨λ“  비동기 μž‘μ—…μ΄ μ²˜λ¦¬λ˜μ–΄ 데이터 μ˜μ‘΄μ„±μ΄ λͺ¨λ‘ ν•΄κ²°λœ μ—˜λ¦¬λ¨ΌνŠΈ 트리(즉, μžλ°”μŠ€ν¬λ¦½νŠΈ 객체)λ₯Ό 생성할 수 있게 λ©λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μ€ κ°μ²΄μ§€λ§Œ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈκ°€ μ•„λ‹Œ κ²½μš°μž…λ‹ˆλ‹€. ν‰ν—˜ν•œ μžλ°”μŠ€ν¬λ¦½νŠΈ 객체이기 λ•Œλ¬Έμ— ν•΄λ‹Ή 객체의 각 값에 λŒ€ν•΄ ν•¨μˆ˜λ₯Ό μž¬κ·€μ μœΌλ‘œ ν˜ΈμΆœν•˜κ³  κ²°κ³Όλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

이λ₯Ό μ‚¬μš©ν•΄ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ‘œ λ Œλ”λ§ν•œ 후에 ν΄λΌμ΄μ–ΈνŠΈλ‘œ 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€. 이제 ν•΄λ‹Ή μ—˜λ¦¬λ¨ΌνŠΈ 트리λ₯Ό renderToStringμ΄λ‚˜ renderToPipeableStream으둜 μ „λ‹¬ν•˜κ±°λ‚˜ μ§λ ¬ν™”ν•΄μ„œ λΈŒλΌμš°μ €λ‘œ 직접 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€. λ¦¬μ•‘νŠΈλŠ” 이λ₯Ό μžμ‹ μ΄ 이해할 수 μžˆλŠ” λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈ 트리둜 ν•΄μ„ν•˜κ³  ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ Œλ”λ§ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ ν•΄μ•Ό ν•  일이 λ‚¨μ•˜μŠ΅λ‹ˆλ‹€. λ°”λ‘œ μ§λ ¬ν™”μž…λ‹ˆλ‹€.

직렬화​

μ§λ ¬ν™”λŠ” 초기 λ‘œλ“œ 쀑에 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ˜¬λ°”λ₯΄λ‘œ 효율적으둜 λ Œλ”λ§λ˜λ„λ‘ 보μž₯ν•˜λŠ” 데 맀우 μ€‘μš”ν•œ μž‘μ—…μž…λ‹ˆλ‹€. μ„œλ²„μ—μ„œ λ Œλ”λ§λœ λ™μΌν•œ 좜λ ₯이 ν΄λΌμ΄μ–ΈνŠΈμ™€ μΌμΉ˜ν•΄μ•Όλ§Œ λ¦¬μ•‘νŠΈκ°€ μ˜¬λ°”λ₯΄κ²Œ μž¬μ‘°μ •ν•˜κ³  차이점을 νŒŒμ•…ν•  수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ„œλ²„μ—μ„œ λ Œλ”λ§λ  λ•Œ, μƒμ„±λœ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” λΈŒλΌμ›†μ–΄λ‘œ 전솑될 수 μžˆλŠ” HTML λ¬Έμžμ—΄λ‘œ λ³€ν™˜λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. 이떄 λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ¬Έμžμ—΄λ‘œ λ³€ν™˜ν•˜λŠ” 과정을 직렬화라고 ν•©λ‹ˆλ‹€.

일반적인 λ¦¬μ•‘νŠΈ μ—ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” λ©”λͺ¨λ¦¬μ— μžˆλŠ” κ°μ²΄μž…λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ—˜λ¦¬λ¨ΌνŠΈλŠ” React.createElementλ₯Ό ν˜ΈμΆœν•˜κ±°λ‚˜ JSX 문법을 μ‚¬μš©ν•΄ μƒμ„±λ©λ‹ˆλ‹€. λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” μ»΄ν¬λ„ŒνŠΈκ°€ μ–΄λ–»κ²Œ λ Œλ”λ§λ μ§€ ν‘œν˜„ν•˜μ§€λ§Œ, 아직 μ‹€μ œ DOM μ—˜λ¦¬λ¨ΌνŠΈλŠ” μ•„λ‹™λ‹ˆλ‹€.

const element = <h1>Hello, world</h1>;

ReactDOMServer.renderToString 같은 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•΄ μ„œλ²„μ—μ„œ λ Œλ”λ§ν•  λ•Œ μ΄λŸ¬ν•œ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλŠ” HTML λ¬Έμžμ—΄λ‘œ μ§λ ¬ν™”λ©λ‹ˆλ‹€. 직렬화 ν”„λ‘œμ„ΈμŠ€λŠ” λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈ 트리λ₯Ό 탐색해 각 μ—˜λ¦¬λ¨ΌνŠΈμ— ν•΄λ‹Ήν•˜λŠ” HTML을 μƒμ„±ν•˜κ³  이λ₯Ό λͺ¨λ‘ 합쳐 ν•˜λ‚˜μ˜ HTML λ¬Έμžμ—΄λ‘œ λ§Œλ“­λ‹ˆλ‹€.

const htmlString = ReactDOMServer.renderToString(element);
// htmlString은 '<h1>Hello, world</h1>'κ°€ λ©λ‹ˆλ‹€.

그런 λ‹€μŒ 이 HTML λ¬Έμžμ—΄μ„ ν΄λΌμ΄μ–ΈνŠΈλ‘œ 전솑해 νŽ˜μ΄μ§€μ˜ 초기 λ§ˆν¬μ—…μœΌλ‘œ μ‚¬μš©ν•©λ‹ˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ΄ ν΄λΌμ΄μ–ΈνŠΈμ— λ‘œλ“œλ˜λ©΄ λ¦¬μ•‘νŠΈλŠ” 이벀트 ν•Έλ“€λŸ¬λ₯Ό μΆ”κ°€ν•˜κ³  동적 μ½˜ν…μΈ λ₯Ό μ±„μš°λ©΄μ„œ DOM을 'ν•˜μ΄λ“œλ ˆμ΄νŠΈ'ν•©λ‹ˆλ‹€.

직렬화 λ‹¨κ³„λŠ” μ—¬λŸ¬ κ°€μ§€ 이유둜 μ€‘μš”ν•©λ‹ˆλ‹€. 첫째, μ„œλ²„κ°€ μ¦‰μ‹œ ν‘œμ‹œν•  수 μžˆλŠ” μ™„μ „ν•œ HTML νŽ˜μ΄μ§€λ₯Ό λΉ λ₯΄κ²Œ ν΄λΌμ΄μ–ΈνŠΈμ— 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ μ‚¬μš©μžκ°€ μ½˜ν…μΈ μ™€ 더 빨리 μƒν˜Έ μž‘μš©ν•˜κ²Œ λ˜μ–΄ νŽ˜μ΄μ§€μ˜ 체감 λ‘œλ”© 속도가 κ°œμ„ λ©λ‹ˆλ‹€.
λ˜ν•œ λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό HTML λ¬Έμžμ—΄λ‘œ μ§λ ¬ν™”ν•˜λ©΄ ν™˜κ²½μ— 관계없이 μΌκ΄€λ˜κ³  예츑 κ°€λŠ₯ν•œ 초기 λ Œλ”λ§μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€. μƒμ„±λœ HTML은 정적이며 μ„œλ²„μ—μ„œ λ Œλ”λ§λ˜λ“  ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ Œλ”λ§λ˜λ“  λ™μΌν•˜κ²Œ ν‘œμ‹œλ©λ‹ˆλ‹€.
끝으둜 μ§λ ¬ν™”λŠ” ν΄λΌμ΄μ–ΈνŠΈ 츑의 ν•˜μ΄λ“œλ ˆμ΄μ…˜ ν”„λ‘œμ„ΈμŠ€λ₯Ό μš©μ΄ν•˜κ²Œ ν•©λ‹ˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ΄ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ‘œλ“œλ˜λ©΄ λ¦¬μ•‘νŠΈλŠ” 이벀트 ν•Έλ“€λŸ¬λ₯Ό μΆ”κ°€ν•˜κ³  동적 μ½˜ν…μΈ λ₯Ό λͺ¨λ‘ μ±„μ›Œμ•Ό ν•©λ‹ˆλ‹€. μ§λ ¬ν™”λœ HTML λ¬Έμžμ—΄μ„ 초기 λ§ˆν¬μ—…μœΌλ‘œ μ‚¬μš©ν•˜λ©΄ λ¦¬μ•‘νŠΈκ°€ μž‘μ—…ν•  수 μžˆλŠ” κ²¬κ³ ν•œ κΈ°λ°˜μ„ 확보해 λ‹€μ‹œ μ‹€ν–‰ν•˜λŠ” ν•˜μ΄λ“œλ ˆμ΄μ…˜ ν”„λ‘œμ„ΈμŠ€λ₯Ό 보닀 효율적이고 μ•ˆμ •μ μœΌλ‘œ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ—…λ°μ΄νŠΈβ€‹

RSCλŠ” μž₯점이 λ§Žμ§€λ§Œ, μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ™€ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλΌλŠ” 두 μ’…λ₯˜μ˜ μ»΄ν¬λ„ŒνŠΈλ₯Ό κ³ λ €ν•΄μ•Ό ν•œλ‹€λŠ” μ μ—μ„œ 생각할 게 λ§Žμ•„μ§„λ‹€λŠ” 단점도 μžˆμŠ΅λ‹ˆλ‹€. μ»΄ν¬λ„ŒνŠΈ μ€‘μ—λŠ” μ„œλ²„ μ»΄ν¬λ„ŒνŠΈκ°€ 될 수 μ—†λŠ” 것도 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

μ‚¬μš©μžκ°€ + λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ μΉ΄μš΄ν„° 값을 1μ”© μ¦κ°€μ‹œν‚€λŠ” κ°„λ‹¨ν•œ μΉ΄μš΄ν„° μ»΄ν¬λ„ŒνŠΈλ₯Ό μƒκ°ν•΄λ΄…μ‹œλ‹€.

function Counter() {
const [count, setCount] = useState(0);

return (
<div>
<h1>μ•ˆλ…• μΉœκ΅¬λ“€, λ‚΄ λ©‹μ§„ μΉ΄μš΄ν„°λ₯Ό 봐쀘!</h1>
<p>λ‚΄ μ†Œκ°œ: λ‚˜λŠ” λ¦¬μ•‘νŠΈλ₯Ό μ’‹μ•„ν•΄. λ°©λͺ…둝에 글을 λ‚¨κ²¨μ€˜!</p>
<p>카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}

이 μ»΄ν¬λ„ŒνŠΈλŠ” 두 κ°€μ§€ 이유 떄문에 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈκ°€ 될 수 μ—†μŠ΅λ‹ˆλ‹€.

  • ν΄λΌμ΄μ–ΈνŠΈ μ „μš© API인 useStateλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 즉, μ„œλ²„λŠ” count의 μ΄ˆκΉƒκ°’μ΄ 무엇인지 μ•Œμ§€ λͺ»ν•˜λ―€λ‘œ 초기 HTML을 λ Œλ”λ§ν•  수 μ—†μŠ΅λ‹ˆλ‹€. μ΄λŠ” μ„œλ²„κ°€ 초기 HTML을 λ Œλ”λ§ν•œ ν›„, 그리고 μ‚¬μš©μžκ°€ μƒν˜Έ μž‘μš©ν•  수 μžˆλŠ” UI ν΄λΌμ΄μ–ΈνŠΈκ°€ λ Œλ”λ§ν•˜κΈ° 전에 λ¬Έμ œκ°€ 될 κ²ƒμž…λ‹ˆλ‹€.
  • ν΄λΌμ΄μ–ΈνŠΈ μ „μš© API인 onClick을 μ‚¬μš©ν•©λ‹ˆλ‹€. μ„œλΈŒλŠ” μΈν„°λž™ν‹°λΈŒν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ„œλ²„μ—μ„œ μ‹€ν–‰ 쀑인 ν”„λ‘œνŽ˜μŠ€λŠ” 클릭할 수 μ—†μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ—μ„œ onClick을 μ‚¬μš©ν•˜κΈ°λž€ λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€. 또 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ˜ λͺ¨λ“  프둭은 직렬화가 κ°€λŠ₯ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ„œλ²„κ°€ 프둭을 직렬화해 ν΄λΌμ΄μ–ΈνŠΈλ‘œ 전솑할 수 μžˆμ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ ν•¨μˆ˜λŠ” 직렬화가 λΆˆκ°€λŠ₯ν•˜λ―€λ‘œ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ—μ„œλŠ” ν•¨μˆ˜λ₯Ό ν”„λ‘­μœΌλ‘œ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ˜ κΈ°λŠ₯을 ν™œμš©ν•˜κ³  μ‹Άλ‹€λ©΄, 바둝 κ°„λ‹¨ν•œ μΉ΄μš΄ν„°λΌκ³  ν•˜λ”λΌλ„ μ„œλ²„ λΆ€λΆ„κ³Ό ν΄λΌμ΄μ–ΈνŠΈ 뢀뢄을 뢄리해야 ν•©λ‹ˆλ‹€.

// μ„œλ²„ μ»΄ν¬λ„ŒνŠΈ
function ServerCounter() {
return (
<div>
<h1>μ•ˆλ…• μΉœκ΅¬λ“€, λ‚΄ λ©‹μ§„ μΉ΄μš΄ν„°λ₯Ό 봐쀘!</h1>
<p>λ‚΄ μ†Œκ°œ: λ‚˜λŠ” λ¦¬μ•‘νŠΈλ₯Ό μ’‹μ•„ν•΄. λ°©λͺ…둝에 글을 λ‚¨κ²¨μ€˜!</p>
<ClientPart />
</div>
);
}

// ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈ
"use client";
function ClientPart() {
const [count, setCount] = useState(0);

return (
<div>
<p>카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}

μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ„œλ²„ λ Œλ”λ§μ΄ κ°€λŠ₯ν•œ λΆ€λΆ„κ³Ό ν΄λΌμ΄μ–ΈνŠΈ λ Œλ”λ§μ΄ κ°€λŠ₯ν•œ 뢀뢄을 κ³ λ €ν•΄μ•Ό ν•©λ‹ˆλ‹€. 이둜 인해 μ•½κ°„μ˜ 고좩이 μƒκΉλ‹ˆλ‹€. κ·ΈλŸΌμ—λ„ 이 μž‘μ—…μ€ 의미 μžˆμŠ΅λ‹ˆλ‹€. μΈν„°λž™ν‹°λΈŒν•œ 뢀뢄을 λ‹΄λ‹Ήν•˜λŠ” μΉ΄μš΄ν„° μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 일뢀λ₯Ό 뢄리해 λƒˆκ³ , 이 μž‘μ€ λΆ€λΆ„λ§Œμ΄ μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ˜ μΌλΆ€λ‘œ μ‚¬μš©μžμ—κ²Œ μ „λ‹¬λ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. λ‚˜λ¨Έμ§€ μ½”λ“œλŠ” ν΄λΌμ΄μ–ΈνŠΈ μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ— ν¬ν•¨λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. κ·Έ κ²°κ³Ό λ„€νŠΈμ›Œν¬λ₯Ό 톡해 μ „λ‹¬λ˜λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ˜ 크기가 ν˜„μ €ν•˜κ²Œ 쀄어 λ‘œλ”© μ‹œκ°„μ΄ 빨라지고 μ„±λŠ₯도 ν–₯μƒλ©λ‹ˆλ‹€. CPU μΈ‘λ©΄μ—μ„œλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό νŒŒμ‹±ν•˜κ³  μ‹€ν–‰ν•˜λŠ” μž‘μ—…μ„ κ°μ†Œν•˜κ³ , λ„€νŠΈμ›Œν¬ μΈ‘λ©΄μ—μ„œλŠ” λ‹€μš΄λ‘œλ“œν•΄μ•Ό ν•˜λŠ” 데이터 양이 μ μ–΄μ§‘λ‹ˆλ‹€. 이것이 λ°”λ‘œ κ°€λŠ₯ν•œ ν•œ λ§Žμ€ μ½”λ“œλ₯Ό μ„œλ²„μ—μ„œλ§Œ λ Œλ”λ§ν•˜κ³  ν΄λΌμ΄μ–ΈνŠΈ λ²ˆλ“€μ—μ„œ μ œκ±°ν•˜λ €λŠ” μ΄μœ μž…λ‹ˆλ‹€.

λ‚΄λΆ€ λ™μž‘β€‹

ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” ν•΄λ‹Ή μ»΄ν¬λ„ŒνŠΈκ°€ ν¬ν•¨λœ 파일 μ΅œμƒλ‹¨μ— "use client" μ§€μ‹œμžλ₯Ό μΆ”κ°€ν•΄ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλ‘œ μ„€μ •λ©λ‹ˆλ‹€.

κ°œλ…μ μœΌλ‘œλŠ” μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜λŠ” μ„œλ²„ κ·Έλž˜ν”„μ™€, ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ ν•„μš”ν•  λ•Œ λ‹€μš΄λ‘œλ“œλ˜μ–΄ μ‹€ν–‰λ˜λŠ” ν•˜λ‚˜ μ΄μƒμ˜ ν΄λΌμ΄μ–ΈνŠΈ λ²ˆλ“€μ΄ μ‘΄μž¬ν•©λ‹ˆλ‹€. κ·Έλ ‡λ‹€λ©΄ λ¦¬μ•‘νŠΈλŠ” μ–Έμ œ μ–΄λŠ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό 가져와 μ‹€ν–‰ν•΄μ•Ό λ˜λŠ”μ§€λ₯Ό μ–΄λ–»κ²Œ νŒŒμ•…ν• κΉŒμš”? μ•žμ„œ λ³΄μ•˜λ˜ μΉ΄μš΄ν„°λ₯Ό 예둜 λ“€κ² μŠ΅λ‹ˆλ‹€.

μΉ΄μš΄ν„° μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ»΄ν¬λ„ŒνŠΈ 트리의 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œ λ Œλ”λ§λ˜κ³ , ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ Œλ”λ§λ©λ‹ˆλ‹€. 트리의 λ£¨νŠΈκ°€ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ΄κΈ° λ•Œλ¬Έμ— 전체 νŠΈλ¦¬λŠ” μ„œλ²„μ—μ„œ λ Œλ”λ§λ©λ‹ˆλ‹€. ν•˜μ§€λ§Œ InteractiveClientPart μ»΄ν¬λ„ŒνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ΄λ―€λ‘œ μ„œλ²„μ—μ„œ λ Œλ”λ§λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λŒ€μ‹ , μ„œλ²„λŠ” ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλ₯Ό μœ„ν•œ ν”Œλ ˆμ΄μŠ€ν™€λ”λ₯Ό λ Œλ”λ§ν•©λ‹ˆλ‹€. 이 ν”Œλ ˆμ΄μŠ€ν™€λ”λŠ” ν΄λΌμ΄μ–ΈνŠΈ λ²ˆλ“€λŸ¬κ°€ μƒμ„±ν•œ νŠΉμ • λͺ¨λ“ˆμ— λŒ€ν•œ μ°Έμ‘°μž…λ‹ˆλ‹€. κ°„λ‹¨νžˆ 말해 '트리의 이 지점에 λ„λ‹¬ν•˜λ©΄ νŠΉμ • λͺ¨λ“ˆμ„ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€'κ³  μ•Œλ € μ£ΌλŠ” κ²ƒμž…λ‹ˆλ‹€.

μ—¬κΈ°μ„œ μ€‘μš”ν•œ 것은 μ„œλ²„κ°€ μ˜¬λ°”λ₯Έ ν΄λΌμ΄μ–ΈνŠΈ λͺ¨λ“ˆμ— λŒ€ν•œ μ°Έμ‘°λ₯Ό μ „μ†‘ν•˜κ³ , ν΄λΌμ΄μ–ΈνŠΈμ˜ λ¦¬μ•‘νŠΈκ°€ ν•΄λ‹Ή μ°Έμ‘°λ₯Ό 기반으둜 빈 뢀뢄을 μ±„μš΄λ‹€λŠ” μ μž…λ‹ˆλ‹€. 이 κ³Όμ •μ—μ„œ λ¦¬μ•‘νŠΈλŠ” λͺ¨λ“ˆ μ°Έμ‘°λ₯Ό ν΄λΌμ΄μ–ΈνŠΈ λ²ˆλ“€μ— μžˆλŠ” μ‹€μ œ λͺ¨λ“ˆλ‘œ κ΅μ²΄ν•©λ‹ˆλ‹€. λ¦¬μ•‘νŠΈλŠ” 이런 방식을 톡해 μ–Έμ œ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλ₯Ό 가져와 μ‹€ν–‰ν•΄μ•Ό ν•˜λŠ”μ§€ νŒŒμ•…ν•©λ‹ˆλ‹€.

μ£Όμ˜ν•  점​

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œλ§Œ μ‹€ν–‰λ˜κ³  ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œλ§Œ μ‹€ν–‰λœλ‹€λŠ” μ˜€ν•΄κ°€ μžˆμ§€λ§Œ 사싀이 μ•„λ‹™λ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ‹€μ œ μ„œλ²„μ—μ„œλ§Œ μ‹€ν–‰λ˜κ³  λ₯΄μ•‘트 μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μ˜λ―Έν•˜λŠ” 객체λ₯Ό 좜λ ₯ν•˜μ§€λ§Œ, ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œλ§Œ μ‹€ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

'μ»΄ν¬λ„ŒνŠΈκ°€ μ‹€ν•΄λœλ‹€'λŠ” 것은 μ»΄ν¬λ„ŒνŠΈλ₯Ό ν‘œν˜„ν•˜λŠ” ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€λŠ” λœ»μž…λ‹ˆλ‹€.

function MyComponent() {
return <div>hello world</div>;
}

'My Componentκ°€ μ‹€ν–‰λœλ‹€'λŠ” 말은 MyComponent ν•¨μˆ˜κ°€ ν”„λ‘­κ³Ό ν•¨κ»˜ ν˜ΈμΆœλ˜μ–΄ λ‹€μŒκ³Ό 같은 ν‰ν—˜ν•œ μžλ°”μŠ€ν¬λ¦½νŠΈ 객체둜 ν‘œν˜„λ˜λŠ” λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨Όν‹€ λ°˜ν™˜ν•œλ‹€λŠ” λœ»μž…λ‹ˆλ‹€.

{
&&typeof: Symbol(react.element),
type: "div",
props: {
children: "hello world",
}
}

이것이 λ°”λ‘œ 'μ»΄ν¬λ„ŒνŠΈκ°€ μ‹€ν–‰λœλ‹€'λŠ” 말의 μ˜λ―Έμž…λ‹ˆλ‹€.

μ„œλ²„ λ Œλ”λ§ 쀑에 ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜κ³  λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 객체λ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€. 그런 λ‹€μŒ μ΄λŸ¬ν•œ μ—˜λ¦¬λ¨ΌνŠΈλŠ” HTML λ¬Έμžμ—΄λ‘œ μ§λ ¬ν™”λ˜μ–΄ λΈŒλΌμš°μ €μ—μ„œ HTML λ§ˆν¬μ—…μ„ λ Œλ”λ§ν•˜λŠ” ν΄λΌμ΄μ–ΈνŠΈλ‘œ μ „μ†‘λ©λ‹ˆλ‹€. λ”°λΌμ„œ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλ„ μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜κ³  λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 일뢀 객체λ₯Ό λ°˜ν™˜ν•œ 후에 μ„œλ²„μ—μ„œ 이λ₯Ό HTML둜 직렬화해 ν΄λΌμ΄μ–ΈνŠΈλ‘œ μ „μ†‘ν•©λ‹ˆλ‹€.

이λ₯Ό 보닀 μ •ν™•ν•˜κ²Œ ν‘œν˜„ν•˜κΈ° μœ„ν•΄ λ‹€μŒκ³Ό 같이 참인 λͺ…μ œλ₯Ό κ΅¬μ„±ν–ˆμŠ΅λ‹ˆλ‹€.

  • μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜λ©° λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 객체λ₯Ό 좜λ ₯ν•œλ‹€.
  • ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜λ©° λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 객체λ₯Ό 좜λ ₯ν•œλ‹€.
  • μ„œλ²„μ—λŠ” ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ˜ λͺ¨λ“  λ¦¬μ•‘νŠΈ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό ν‘œν˜„ν•˜λŠ” μ»€λ‹€λž€ 객체가 μžˆλ‹€.
  • 이 κ°μ²΄λŠ” λ¬Έμžμ—΄λ‘œ λ³€ν™˜λ˜μ–΄ ν΄λΌμ΄μ–ΈνŠΈλ‘œ μ „μ†‘λœλ‹€.
  • 이 μ‹œμ λΆ€ν„° μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ‹€ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.
  • 이 μ‹œμ λΆ€ν„° ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œλ§Œ μ‹€ν–‰λœλ‹€.

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈ κ·œμΉ™β€‹

직렬화 κ°€λŠ₯성이 κ°€μž₯ μ€‘μš”ν•˜λ‹€β€‹

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ—μ„œλŠ” λͺ¨λ“  프둭을 직렬화할 수 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. μ΄λŠ” μ•žμ„œ μ„€λͺ…ν•œ κ²ƒμ²˜λŸΌ μ„œλ²„κ°€ 프둭을 직렬화해 ν΄λΌμ΄μ–ΈνŠΈλ‘œ 전솑할 수 μžˆμ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. λ”°λΌμ„œ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ—μ„œ ν•¨μˆ˜ λ“± 직렬화할 수 μ—†λŠ” 값을 ν”„λ‘­μœΌλ‘œ μ‚¬μš©ν•˜μ§€ λͺ»ν•©λ‹ˆλ‹€.

λΆ€μž‘μš©μ΄ μžˆλŠ” ν›… κΈˆμ§€β€‹

μ„œλ²„ ν™˜κ²½μ€ ν΄λΌμ΄μ–ΈνŠΈμ™€ μ™„μ „νžˆ λ‹€λ¦…λ‹ˆλ‹€. μΈν„°λž™ν‹°λΈŒν•˜μ§€λ„ μ•Šκ³ , DOMμ΄λ‚˜ window 객체도 μ—†μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ λΆ€μž‘μš©μ΄ μžˆλŠ” 훅은 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ—μ„œ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλΌκ³  ν•˜λ”λΌλ„ μƒνƒœ, 효과, λΈŒλΌμš°μ € μ „μš© API에 μ˜μ‘΄ν•˜μ§€ μ•ŠλŠ” 훅은 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€λ©΄ useRef 훅이 κ·Έλ ‡μŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ œμ•½μ΄ λ°˜λ“œμ‹œ λ‚˜μœ 것은 μ•„λ‹™λ‹ˆλ‹€. 였히렀 이λ₯Ό 톡해 μ»΄ν¬λ„ŒνŠΈ μž‘μ—…μ„ 보닀 μ•ˆμ „ν•œ λ°©ν–₯으둜 μœ λ„ν•˜κΈ° λ–„λ¬Έμž…λ‹ˆλ‹€.

μƒνƒœλŠ” λ™μΌν•˜μ§€ μ•Šλ‹€β€‹

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈμ˜ μƒνƒœλŠ” ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈ μƒνƒœμ™€ λ™μΌν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œ λ Œλ”λ§λ˜κ³  ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ Œλ”λ§λ˜κΈ° λ–„λ¬Έμž…λ‹ˆλ‹€. μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈμ˜ κ΄€κ³„λŠ” 1:N의 κ΄€κ³„λ‘œ ν•˜λ‚˜μ˜ μ„œλ²„κ°€ λ‹€μˆ˜μ˜ ν΄λΌμ΄μ–ΈνŠΈμ— λŒ€μ‘ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ νŠΉμ„±μƒ μ„œλ²„μ˜ μƒνƒœκ°€ μ—¬λŸ¬ ν΄λΌμ΄μ–ΈνŠΈμ— 곡유될 수 있고, 이둜 인해 ν΄λΌμ΄μ–ΈνŠΈμ˜ μƒνƒœκ°€ λ‹€λ₯Έ ν΄λΌμ΄μ–ΈνŠΈμ— λ…ΈμΆœλ  μœ„ν—˜μ΄ λ†’μŠ΅λ‹ˆλ‹€.

ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ‘œ κ°€μ Έμ˜¬ 수 없닀​

ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈμ—μ„œλŠ” μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό κ°€μ Έμ˜¬ 수 μ—†μŠΊλ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œλ§Œ μ‹€ν–‰λ˜μ§€λ§Œ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” λΈŒλΌμš°μ €λ₯Ό 포함해 μ–‘μͺ½ λͺ¨λ‘μ—μ„œ μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

"use client";
import { ServerComponent } from "./ServerComponent";

function ClientComponent() {
return (
<div>
<h1>제 λ©‹μ§„ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈ μ’€ λ΄μ£Όμ„Έμš”!</h1>
<ServerComponent />
</div>
);
}

μ΄λŠ” λΆˆκ°€λŠ₯ν•œ μž‘μ—…μž…λ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” 였직 μ„œλ²„μ—μ„œλ§Œ μ‹€ν–‰λ˜λ©°, μ—¬κΈ°μ„œ λΆˆλŸ¬μ˜€λ €λŠ” μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” Node.js API와 같이 ν΄λΌμ΄μ–ΈνŠΈ ν™˜κ²½μ—μ„œλŠ” μ‚¬μš©ν•  수 μ—†λŠ” μš”μ†Œλ₯Ό 포함할 수 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 이λ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ‹€ν–‰ν•˜λ €κ³  ν•˜λ©΄ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” 프둭을 톡해 μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ‘°ν•©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import { ServerComponent } from "./ServerComponent";

async function TheParentOfBothComponents() {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
);
}

μ΄λ ‡κ²Œ μž‘μ„±ν•˜λ©΄ λ¬Έμ œμ—†μ΄ λ™μž‘ν•©λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈμ—μ„œ λͺ…μ‹œμ μœΌλ‘œ importλ₯Ό μ‚¬μš©ν•΄ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό κ°€μ Έμ˜¨ 것이 μ•„λ‹ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. λŒ€μ‹  λΆ€λͺ¨ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈκ°€ μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈμ˜ ν”„λ‘­μœΌλ‘œ μ „λ‹¬ν•©λ‹ˆλ‹€. import μ‚¬μš©μ΄ κΈˆμ§€λœ μœ μΌν•œ μ΄μœ λŠ” ν΄λΌμ΄μ–ΈνŠΈ λ²ˆλ“€μ— μ„œλ²„ μ»΄ν¬λ„ŒνŠΈκ°€ ν¬ν•¨λ˜λŠ” 것을 λ°©μ§€ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λ²ˆλ“€λŸ¬λŠ” import 문만 κ°μ„œν•˜μ§€ ν”„λ‘­μœΌλ‘œ μ „λ‹¬λ˜λŠ” 컴포먼트 κ΅¬μ„±μ—λŠ” 주의λ₯Ό κΈ°μšΈμ΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” λ‚˜μ˜μ§€ μ•Šλ‹€β€‹

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈκ°€ λ„μž…λ˜κΈ° μ „, λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈμ—λŠ” ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλΌλŠ” ν•œ μ’…λ₯˜λ§Œ μ‘΄μž¬ν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ 말해 기쑴의 λͺ¨λ“  μ»΄ν¬λ„ŒνŠΈκ°€ ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλΌλŠ” 의미이며, κ·Έλž˜λ„ μ•„λ¬΄λŸ° λ¬Έμ œκ°€ μ—†μ—ˆμŠ΅λ‹ˆλ‹€. ν΄λΌμ΄μ–ΈνŠΈ μ»΄ν¬λ„ŒνŠΈλŠ” λ‚˜μ˜μ§€ μ•ŠμœΌλ©° 사라지지 μ•Šμ„ κ²ƒμž…λ‹ˆλ‹€. μ—¬μ „νžˆ λ¦¬μ•‘νŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 핡심이며, μ•žμœΌλ‘œλ„ κ°€μž₯ 널리 μž‘μ„±λ˜λŠ” μ’…λ₯˜μ˜ μ»΄ν¬λ„ŒνŠΈμΌ κ²ƒμž…λ‹ˆλ‹€.

μ„œλ²„ μ•‘μ…˜β€‹

RSCλŠ” "use server" μ§€μ‹œμžλ₯Ό μ‚¬μš©ν•΄ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμ—μ„œ ν˜ΈμΆœν•  수 μžˆλŠ” μ„œλ²„ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ”λ°, μ΄λŸ¬ν•œ ν•¨μˆ˜λ₯Ό κ°€λ¦¬μΌœ μ„œλ²„ μ•‘μ…˜μ΄λΌκ³  ν•©λ‹ˆλ‹€.

비동기 ν•¨μˆ˜μ˜ λ³Έλ¬Έ 첫 쀄에 "use server"λ₯Ό μΆ”κ°€ν•˜λ©΄, λ¦¬μ•‘νŠΈμ™€ λ²ˆλ“€λŸ¬λŠ” 이 ν•¨μˆ˜λ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ ν˜ΈμΆœν•  수 μžˆμ§€λ§Œ μ„œλ²„μ—μ„œλ§Œ μ‹€ν–‰λ˜λŠ” ν•¨μˆ˜λ‘œ μ·¨κΈ‰ν•©λ‹ˆλ‹€. ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ„œλ²„ μ•‘μ…˜μ„ ν˜ΈμΆœν•  λ–„, ν•¨μˆ˜μ— μ „λ‹¬λ˜λŠ” λͺ¨λ“  μΈμˆ˜λŠ” μ§λ ¬ν™”λ˜μ–΄ λ„€νŠΈμ›Œν¬λ₯Ό 톡해 μ„œλ²„μ— μ „λ‹¬λ©λ‹ˆλ‹€. μ„œλ²„ μ•‘μ…˜μ΄ 값을 λ°˜ν™˜ν•˜λ©΄, λ°˜ν™˜λœ 값은 μ§λ ¬ν™”λ˜μ–΄ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ λ°˜ν™˜λ©λ‹ˆλ‹€.

ν•¨μˆ˜λ§ˆλ‹€ 일일이 "use server"둜 μΆ”κ°€ν•˜λŠ” λŒ€μ‹ , 파일 상단에 "use server" μ§€μ‹œμžλ₯Ό μΆ”κ°€ν•΄ 파일 λ‚΄μ—μ„œ 내보내진 ν•¨μˆ˜λ₯Ό μ„œλ²„ μ•‘μ…˜μœΌλ‘œ ν‘œμ‹œν•˜λŠ” 방법도 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμ—μ„œλ„ import λ₯Ό μ‚¬μš©ν•΄ 이 ν•¨μˆ˜λ₯Ό κ°€μ Έμ˜€κ³  μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

폼과 데이터 μ‘°μž‘β€‹

// App.js
async function requestUsername(formData) {
'use server';
const username = formData.get('username');

// ...
}

export default function App() {
return (
<form action={requestUsername}>
<input type="text" name="username" />
<button type="submit">μš”μ²­</button>
</form>
)
}

이 μ˜ˆμ—μ„œ requestUsername은 <form>으둜 μ „λ‹¬λ˜λŠ” μ„œλ²„ μ•‘μ…˜μž…λ‹ˆλ‹€. μ‚¬μš©μžκ°€ 이 양식을 μ œμΆœν•˜λ©΄ μ„œλ²„μ˜ requestUsername ν•¨μˆ˜μ— λ„€νŠΈμ›Œν¬ μš”μ²­μ΄ μ „λ‹¬λ©λ‹ˆλ‹€. νΌμ—μ„œ μ„œλ²„ μ•‘μ…˜μ„ ν˜ΈμΆœν•˜λ©΄, λ¦¬μ•‘νŠΈλŠ” 폼의 FormDataλ₯Ό μ„œλ²„ μ•‘μ…˜μ˜ 첫 번째 인수둜 μ œκ³΅ν•©λ‹ˆλ‹€.

μ„œλ²„ μ•‘μ…˜μ€ 폼 μ•‘μ…˜μ— μ „λ‹¬ν•¨μœΌλ‘œμ¨ λ¦¬μ•‘νŠΈλŠ” 폼을 μ μ§„μ μœΌλ‘œ ν–₯μƒν•©λ‹ˆλ‹€. λ‹€μ‹œ 말해 μžλ°”μŠ€ν¬λ¦½νŠΈ λ²ˆλ“€μ΄ μ „λΆ€ λ‘œλ“œ λ˜κΈ°μ „μ—λ„ 폼을 μ‚¬μš©ν•˜κ³  전솑할 수 μžˆμŠ΅λ‹ˆλ‹€.

폼 외뢀​

μ„œλ²„ μ•‘μ…˜μ€ μ„œλ²„ μ—”λ“œν¬μΈνŠΈλ‘œ λ…ΈμΆœλ˜λ©° ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œ μ–΄λ””μ—μ„œλ“  ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.

폼이 μ•„λ‹Œ κ³³μ—μ„œ μ„œλ²„ μ•‘μ…˜μ„ μ‚¬μš©ν•˜λŠ” 경우, νŠΈλžœμ§€μ…˜ λ‚΄λΆ€μ—μ„œλ„ μ„œλ²„ μ•‘μ…˜μ„ ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 λ‘œλ”© λ©”μ‹œμ§€λ₯Ό ν‘œμ‹œν•˜κ³ , 낙관적인 μƒνƒœ μ—…λ°μ΄νŠΈλ₯Ό 보여주며, μ˜ˆμƒμΉ˜ λͺ»ν•œ 였λ₯˜λ₯Ό μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

"use client";

import { useState, useTransition } from "react";

function LikeButton() {
const [isPending, startTransition] = useTransition();
const [likeCount, setLikeCount] = useState(0);

const incrementLike = async () => {
"use server";
return likeCount + 1;
};

const onClick = () => {
startTransition(async () => {
// μ„œλ²„ μ•‘μ…˜μ—μ„œ ν”„λΌλ―ΈμŠ€κ°€ λ°˜ν™˜λ˜λ―€λ‘œ awaitλ₯Ό μ‚¬μš©ν•΄ λ°˜ν™˜λ˜λŠ” 값을 μ½μŠ΅λ‹ˆλ‹€.
const currentCount = await incrementLike();
setLikeCount(currentCount);
});
};

return (
<>
<p>μ’‹μ•„μš” 수: {likeCount}</p>
<button onClick={onClick} disabled={isPending}>
μ’‹μ•„μš”
</button>
</>
);
}

μ„œλ²„ μ•‘μ…˜μ€ ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œμ—μ„œ μ„œλ²„ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  수 있게 ν•˜λŠ” λ¦¬μ•‘νŠΈμ˜ κ°•λ ₯ν•œ μƒˆ κΈ°λŠ₯μž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ΄λŸ¬ν•œ μ§€μ‹œμžλ₯Ό κΈ°λ³Έ λ¦¬μ•‘νŠΈμ—μ„œ μ‚¬μš©ν•˜κΈ°λŠ” λ‹€μ†Œ 번거둭고 λ§Žμ€ μ„€μ • μž‘μ—…μ΄ ν•„μš”ν•˜λ―€λ‘œ λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ ν”„λ ˆμž„μ›Œν¬λ₯Ό 톡해 μ‚¬μš©ν•˜κΈ°λ₯Ό ꢌμž₯ν•©λ‹ˆλ‹€.