๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป dev

[โš›๏ธ React conf 2024] ๋‘ ๋Œ€์˜ ์ปดํ“จํ„ฐ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ฆฌ์•กํŠธ (React for Two Computers | Dan Abramov)

 

 

 

2024.09.24 - [๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป dev] - [โš›๏ธ React Conf 2024] ๋ฆฌ์•กํŠธ 19์—์„œ ์ƒˆ๋กœ์›Œ์ง„ ๊ฒƒ๋“ค (What's new in React 19 | Lydia Hallie)

 

[โš›๏ธ React Conf 2024] ๋ฆฌ์•กํŠธ 19์—์„œ ์ƒˆ๋กœ์›Œ์ง„ ๊ฒƒ๋“ค (What's new in React 19 | Lydia Hallie)

What's new in React 19 | Lydia Hallie์•ฝ 2 ๋‹ฌ ์ „์— REACT CONF 2024๊ฐ€ ์—ด๋ ธ๋‹ค.์—ฌ๋Ÿฌ ํ† ํฌ๋“ค์ด ์ง„ํ–‰๋˜์—ˆ์—ˆ๋Š”๋ฐ, ๊ทธ์ค‘ ๋”ฐ๋ˆ ๋”ฐ๊ทผ(?)ํ•œ React 19์˜ ์ƒˆ ์†Œ์‹๋“ค์„ ์‚ดํŽด๋ณด๊ณ ์ž ํ•œ๋‹ค.canary ๋ฒ„์ „์˜ ๋ฆฌ์•กํŠธ๋ฅผ ์“ฐ๊ณ  ์žˆ์—ˆ๋‹ค๋ฉด

pyotato-dev.tistory.com

์ด์ „ ๊ธ€์€ ๋ฆฌ์•กํŠธ 19์—์„œ ์ƒˆ๋กœ์›Œ์ง„ ๊ธฐ๋Šฅ๋“ค์ด๋‚˜ ๊ฐœ์„ ๋œ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์‚ดํŽด๋ดค์—ˆ๋‹ค.
์˜ค๋Š˜์€ Dan Abramov๊ฐ€ ๋ฐœํ‘œํ•œ "React for Two Computers"์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

ํ† ํฌ ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ Dan์€ ํ•ด๋‹น ์ฃผ์ œ์— ๋Œ€ํ•œ ํ† ํฌ๋ฅผ ๊ธ€๋กœ ํฌ์ŠคํŒ…ํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์ฐจ๋ก€ ์‹œ๋„ํ•ด ๋ดค์ง€๋งŒ,
"ํ† ํฌ" ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค์ด ์žˆ๋Š” ๋ถ€๋ถ„๋“ค์ด "๊ธ€"๋กœ์จ๋Š” ์ „๋‹ฌํ•˜๊ธฐ ์–ด๋ ค์šด ์ ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ–ˆ๋‹ค.

๋œฌ๊ธˆ์—†์ด ์™œ ํ† ํฌ์™€ ํฌ์ŠคํŠธ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๋‚˜ ์‹ถ๊ฒ ์ง€๋งŒ,
์˜ค๋Š˜ ์ฃผ์ œ๋Š” ํ† ํฌ(ํ˜„์žฌ, ํด๋ผ์ด์–ธํŠธ)์™€ ํฌ์ŠคํŠธ(๊ณผ๊ฑฐ, ์„œ๋ฒ„)์™€ ๋ฐ€์ ‘ํ•œ ๋น„์œ ์ด๋ฏ€๋กœ ๊ทธ ํŠน์„ฑ์„ ๊ณ ๋ คํ•˜๊ณ  ํ† ํฌ๋ฅผ ๋“ค์œผ๋ฉด ์ดํ•ดํ•˜๊ธฐ ๋” ์‰ฌ์šด ๊ฑฐ ๊ฐ™๋‹ค.

 

ํ† ํฌ๋Š” ํผํฌ๋จผ์Šค์ด์ž ์Šคํ† ๋ฆฌ๋ผ๊ณ  ํ•œ๋‹ค.
๊ณต์—ฐ์ฒ˜๋Ÿผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ง์„ ํ•˜๊ณ  ํ–‰๋™์„ ๋ณด์—ฌ์ฃผ๊ธฐ๋„ ํ•œ๋‹ค๋Š” ์ ์—์„œ ํผํฌ๋จผ์Šค๊ณ ,

ํ† ํฌ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด ์ „๋‹ฌํ•  ๋‚ด์šฉ์ด ์žˆ๋‹ค๋Š” ์ ์—์„œ ์Šคํ† ๋ฆฌ์ด๋‹ค. 

ํ˜„์žฌ์˜ ํ† ํฌ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” Dan๊ณผ ๊ณผ๊ฑฐ์˜ ๋ฐœํ‘œ์ค€๋น„๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” Dan, ์ด ๋‘ ์ฃผ์ฒด ๊ฐ„์˜ ์ฝœ๋ผ๋ณด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค.


์‹œ๊ณต๊ฐ„์ ์œผ๋กœ ์ด ๋‘ Dan์€ ๊ณต์กดํ•  ์ˆ˜ ์—†์ง€๋งŒ ๊ณผ๊ฑฐ์™€ ํ˜„์žฌ์˜ Dan ๊ฐ„์—๋Š” ์–ด๋– ํ•œ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์ด ์žˆ๋‹ค.

"ํ† ํฌ"๋ผ๋Š” ๊ฒƒ์„ ์™„์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ณผ๊ฑฐ์˜ Dan์ด ๋ฐœํ‘œ ์ฃผ์ œ์— ๋Œ€ํ•œ ์ž๋ฃŒ(์Šคํฌ๋ฆฝํŠธ)๋ฅผ ์ค€๋น„ํ•ด์•ผ ํ•˜๊ณ ,

ํ˜„์žฌ์˜ Dan์€ ํ•ด๋‹น ์ž๋ฃŒ๋ฅผ ๊ฐ€์ง€๊ณ  ๋ฐœํ‘œ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค.

 

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฎค์ง€์ปฌ ๊ณต์—ฐ์„ ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด, ๊ณต์—ฐ์„ ํ•˜๊ธฐ ์œ„ํ•œ ๋Œ€๋ณธ์ด ์กด์žฌํ•ด์•ผ ํ•˜๊ณ , ๊ณต์—ฐ์„ ํ•˜๋Š” ๋ฐฐ์šฐ๋“ค์€ ํ•ด๋‹น ๋Œ€๋ณธ์„ ์—ฐ๊ธฐํ•ด์•ผ ๋ฎค์ง€์ปฌ์ด ์™„์„ฑ๋œ๋‹ค. ๋Œ€๋ณธ๋งŒ ์ผ๋‹ค๊ณ  ๋ฎค์ง€์ปฌ ๊ณต์—ฐ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์—†๊ณ , ๋ฎค์ง€์ปฌ ๋ฐฐ์šฐ๊ฐ€ ๋Œ€๋ณธ ์—†๋Š” ์—ฐ๊ธฐ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค๊ณ  ๋ฎค์ง€์ปฌ ๊ณต์—ฐ์ด๋ผ๊ณ  ๋ณด๊ธฐ ์–ด๋ ต๋‹ค.

 

์ด ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์€ "์ปดํ“จํ„ฐ ์„ธ๊ณ„"์—์„œ๋„ ์œ ์‚ฌํ•˜๊ฒŒ ์กด์žฌํ•˜๋Š”๋ฐ, ์˜ค๋Š˜์˜ ์ฃผ์ œ๊ฐ€ ์ด ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ์˜ ๊ด€๊ณ„ ๋Œ€ํ•œ ๊ฒƒ์ด๋‹ค.

 

์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋…ผํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฉด์ด ์žˆ๊ฒ ์ง€๋งŒ, Dan์€ ๊ทธ์ค‘ "์ „ํ†ต์ ์ธ ์ฝ˜ํ…์ŠคํŠธ์—์„œ์˜ ๋‘ ๋จธ์‹  (์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋žจ)"์— ๋Œ€ํ•ด ๋‹ค๋ฃฌ๋‹ค. ์ฆ‰, "์ „ํ†ต์ ์ธ ์›น๊ฐœ๋ฐœ์—์„œ์˜ request/response ๋ชจ๋ธ"์˜ ์ฝ˜ํ…์ŠคํŠธ์—์„œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ ์–ด๋–ค ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜๊ณ , ์„œ๋ฒ„๊ฐ€ html/์Šคํฌ๋ฆฝํŠธ ๋“ฑ์˜ ์‘๋‹ต์„ ํ•œ๋‹ค.

 

์ด ๊ด€๊ณ„์— ๋Œ€ํ•ด์„œ ๋” ์‚ดํŽด๋ณด๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž. ์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” ๋žœ๋ค์œผ๋กœ ๊ณ ์–‘์ด ์ด๋ฆ„์„ ๊ณจ๋ผ์ฃผ๋Š” ์งง์€ ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

 

const catNames = ['Alonzo', 'Bill Bailey', 'Bombalurina', 'Electra', 'Plato'];
function onClick(){
	const response = await fetch('/api/cat-names');
    const json = await response.json();
    const {catNames} = json;
    const index = Math.floor(Math.random() * catNames.length);
    const catName = catNames[index];
    document.body.innerText = catName;
}

 

ํ•˜์ง€๋งŒ ๊ณ ์–‘์ด ์ด๋ฆ„ (catNames)์ฒ˜๋Ÿผ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ž๋ฃŒ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ข€ ๋” ์œ ์—ฐํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ์ฝ๊ฑฐ๋‚˜ ์ฑ—์ง€ํ”ผํ‹ฐ์—๊ฒŒ ๋ฌผ์–ด๋ณด๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ๋‹ค. 

 

์ „ํ†ต์ ์ธ ๋ฐฉ์‹์„ ๋”ฐ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด api์— ์š”์ฒญ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

// client.ts
async function onClick(){
	const response = await fetch('/api/cat-names');
    const json = await response.json();
    const {catNames} = json;
    const index = Math.floor(Math.random() * catNames.length);
    const catName = catNames[index];
    document.body.innerText = catName;

}

 

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด api ์‘๋‹ต์„ ๋ฐ›์•„์˜ค๊ธฐ๊นŒ์ง€์˜ ์‹œ๊ฐ„์ฐจ ๋•Œ๋ฌธ์— ์ฆ‰๊ฐ์ ์œผ๋กœ ํ™”๋ฉด์— ์ด๋ฆ„์ด ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.

throttle ์„ค์ •์œผ๋กœ ์ธํ„ฐ๋„ท์ด ๋Š๋ฆฐ ํ™˜๊ฒฝ์„ ๋ชจ๋ฐฉํ•œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

์œ ์ € ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋žœ๋” ๋œ ์‹œ์ ์—๋Š” ๊ณ ์–‘์ด ์ด๋ฆ„์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— api๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚ด๋ ค์งˆ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค.

๋งŒ์•ฝ์— ์ธํ„ฐ๋„ท์ด ์•„์˜ˆ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋ผ๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณด์ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ์ƒํ™ฉ์—์„œ๋Š” ์ด๋Ÿฐ ๋™์ž‘ ๋ฐฉ์‹์ด ๋ฌธ์ œ ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋งํฌ๋ฅผ ํด๋ฆญํ•˜๊ฑฐ๋‚˜, ํผ์„ ์ œ์ถœํ•˜๋Š” ๋™์ž‘์€ ๋‹น์—ฐํžˆ ์„œ๋ฒ„๋ฅผ ํ†ตํ•ด ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒŒ ๋‹น์—ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์—,

๋”œ๋ ˆ์ด๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒŒ ์ง์ž‘ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

ํ•˜์ง€๋งŒ ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ๋™์ž‘๋“ค์ด ๋™๊ธฐ์ (latency ์ตœ์†Œํ™”)์œผ๋กœ ์ด๋ฃจ์–ด์กŒ์œผ๋ฉด ์ข‹๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ํŽ˜์ด์ง€์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ์ƒํƒœ๊ฐ€ ์•„๋‹Œ ํŽ˜์ด์ง€๊ฐ€ ๋ณด์ด๋Š” ๋™์‹œ์—  ํŽ˜์ด์ง€์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•จ๊ป˜ ๋ณด์ด๊ธฐ๋ฅผ ์›ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•˜๋Š” ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์„๊นŒ?

ํด๋ผ์ด์–ธํŠธ์˜ ์ž…์žฅ์—์„œ ์‚ดํŽด๋ณด๋ฉด, ์–ด์จŒ๋“  api ์š”์ฒญ์„ ํ•˜๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ๋„์ฐฉํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค๋Š” ์ ์—์„œ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ์—†์–ด ๋ณด์ธ๋‹ค.

๊ทธ๋Ÿผ ์„œ๋ฒ„ ์ฝ”๋“œ์—์„œ ์† ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ์žˆ์„๊นŒ? 

 

๋‹ค์Œ์€ api/cat-names์˜ ์„œ๋ฒ„ ์ฝ”๋“œ๋‹ค.

import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/api/cat-names') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const json = { catNames };
    return json;
  }
  if (url === '/') {
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
        <script src="client.ts"></script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

ํ•œ ๊ฐ€์ง€ ์ง‘์ค‘ํ•ด์„œ ๋ณผ ๋ถ€๋ถ„์€ <script src="client.ts"></script>์ด๋‹ค. 

์ด ๋ถ€๋ถ„์€ ์œ„์—์„œ ์ž‘์„ฑํ–ˆ๋˜ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

์„œ๋ฒ„ ์ฝ”๋“œ๋Š” ์‚ฌ์‹ค ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์ด๋‹ค.

import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/api/cat-names') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const json = { catNames };
    return json;
  }
  if (url === '/') {
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
      	<script>
            async function onClick(){
                const response = await fetch('/api/cat-names');
                const json = await response.json();
                const {catNames} = json;
                const index = Math.floor(Math.random() * catNames.length);
                const catName = catNames[index];
                document.body.innerText = catName;
            }
        </script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

์ด ์ „๊นŒ์ง€๋Š” ์„œ๋ฒ„ ์ฝ”๋“œ์™€ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์„œ๋กœ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜(์š”์ฒญ/์‘๋‹ต ์ฃผ๊ณ ๋ฐ›๊ธฐ)ํ•˜๋Š” ๋ณ„๊ฐœ์˜ ๋‘ ๊ฐœ์˜ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๋ณด์•˜๋‹ค๋ฉด, 

์ง€๊ธˆ์˜ ์ฝ”๋“œ๋กœ ๋ดค์„ ๋•Œ๋Š” ํ•˜๋‚˜์˜ ํ”„๋กœ๊ทธ๋žจ์ด ๋‘ ๊ฐœ์˜ ์ปดํ“จํ„ฐ, ๋‘ ๊ฐœ์˜ ๋‹จ๊ณ„๋กœ ๋™์ž‘ํ•œ๋‹ค๋Š” ๊ด€์ ์œผ๋กœ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด ๊ด€์ ์œผ๋กœ ์ƒ๊ฐ์„ ํ•ด๋ณด๋ฉด ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์„ ๋– ์˜ฌ๋ฆด ์ˆ˜ ์žˆ๋‹ค.

 

๋จผ์ € ํด๋ฆญ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด aysnc๋ฅผ ์ œ๊ฑฐํ•ด ๋ณด์ž.

import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/api/cat-names') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const json = { catNames };
    return json;
  }
  if (url === '/') {
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
      	<script>
            // โœจ ๋ณ€๊ฒฝ
            function onClick(){
                const response = await fetch('/api/cat-names');
                const json = await response.json();
                const {catNames} = json;
                const index = Math.floor(Math.random() * catNames.length);
                const catName = catNames[index];
                document.body.innerText = catName;
            }
        </script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

ํ•˜์ง€๋งŒ api ํ˜ธ์ถœ ์ฝ”๋“œ๋Š” await์ด๋ฏ€๋กœ async์™€ ์ง์„ ์ด๋ฃจ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๋ถ€๋ถ„์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

๋ฆฌ์•กํŠธ์—๋Š” 'lifting state up'๋ผ๋Š” ๊ฒƒ์ด ์žˆ๋‹ค. ์ด๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ state๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ž์‹(ํ•˜์œ„) ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹์ธ๋ฐ, 

๋ฐ์ดํ„ฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋Œ์–ด์˜ฌ๋ฆด(lift up) ์ˆ˜ ์—†์„๊นŒ? state๋ฅผ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ ๋Œ์–ด์˜ฌ ๋ฆฌ ๋“ฏ์ด, ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ€๋ชจ ์ปดํ“จํ„ฐ์ธ ์„œ๋ฒ„๋กœ ๋Œ์–ด์˜ฌ๋ฆด ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?

 

๋‹ค์Œ๊ณผ ๊ฐ™์ด fetch ํ•˜๋Š” ์ฝ”๋“œ ๋ถ€๋ถ„์„ ์„œ๋ฒ„๋กœ ๋Œ์–ด์˜ฌ๋ ค๋ณด์ž.

import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/api/cat-names') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const json = { catNames };
    return json;
  }
  if (url === '/') {
    // โœจ ๋ณ€๊ฒฝ
    const response = await fetch('/api/cat-names');
    const json = await response.json();
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
      	<script>
            function onClick(){
                const {catNames} = json;
                const index = Math.floor(Math.random() * catNames.length);
                const catName = catNames[index];
                document.body.innerText = catName;
            }
        </script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

์ถ”๊ฐ€๋กœ ์ด์ œ fetch๊ฐ€ ์„œ๋ฒ„์—์„œ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜ธ์ŠคํŠธ๋ฅผ ๋ช…์‹œํ•ด ์ฃผ์ž.

import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/api/cat-names') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const json = { catNames };
    return json;
  }
  if (url === '/') {
    // โœจ ๋ณ€๊ฒฝ
    const response = await fetch('http://localhost:3000/api/cat-names');
    const json = await response.json();
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
      	<script>
            function onClick(){
                const {catNames} = json;
                const index = Math.floor(Math.random() * catNames.length);
                const catName = catNames[index];
                document.body.innerText = catName;
            }
        </script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

ํ•˜์ง€๋งŒ ์‹คํ–‰์„ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด json์— ๋Œ€ํ•œ reference ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์ค‘์ฒฉํ•จ์ˆ˜์˜€๋‹ค๋ฉด ํด๋กœ์ € ๋•๋ถ„์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ด๋‹ค.

ํ•˜์ง€๋งŒ ํ˜„์žฌ ์ฝ”๋“œ๋Š” ๋„คํŠธ์›Œํฌ ์ƒ์—์„œ์˜ ํด๋กœ์ €๋ฅผ ์ ์šฉํ•˜๋ ค๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

json์˜ ๋ชฉ์ ์€ ๋„คํŠธ์›Œํฌ ์ƒ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณธ ํ”„๋กœ๊ทธ๋žจ์€ ํ”„๋กœ๊ทธ๋žจ์„ string์œผ๋กœ ์ „์†กํ•œ๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ”„๋กœ๊ทธ๋žจ๊ณผ ๊ฐ™์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด json์„ string์œผ๋กœ ๋ณ€๊ฒฝํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/api/cat-names') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const json = { catNames };
    return json;
  }
  if (url === '/') {
    const response = await fetch('http://localhost:3000/api/cat-names');
    const json = await response.json();
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
      	<script>
            function onClick(){
                // โœจ ๋ณ€๊ฒฝ
                const {catNames} = ${JSON.stringify(json)};
                const index = Math.floor(Math.random() * catNames.length);
                const catName = catNames[index];
                document.body.innerText = catName;
            }
        </script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ๋‚˜์„œ ๋‹ค์‹œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ์ด๋ฏธ ๊ฐ™์ด ์™”๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋‹ˆ ๊ณ ์–‘์ด ์ด๋ฆ„์„ ํŒŒ์ผ์—์„œ ์ฝ์–ด์˜จ๋‹ค๋Š” ์—ญํ•  ํ•˜๋‚˜๋ฟ์ด๋ฏ€๋กœ api๊ฐ€ ๊ตณ์ด ํ•„์š” ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด๋‹น ๋ถ€๋ถ„์„ ๋ฐ”๊ฟ”๋ณด์ž.

import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const json = await response.json();
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
      	<script>
            function onClick(){
                // โœจ ๋ณ€๊ฒฝ
                const {catNames} = ${JSON.stringify(json)};
                const index = Math.floor(Math.random() * catNames.length);
                const catName = catNames[index];
                document.body.innerText = catName;
            }
        </script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

response์™€ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์‚ดํŽด๋ณด๋ฉด ๋ฐ์ดํ„ฐ ํ๋ฆ„์— ๋Œ€ํ•ด์„œ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.


response๋กœ ๋ฐ›์€ catNames๋Š” ๋งค์šฐ ๊ธด๋ฐ, ์‹ค์ œ๋กœ ์šฐ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ณ ์–‘์ด ์ด๋ฆ„์€ ํ•˜๋‚˜๋ฟ์ด๋‹ค.

์ฝ”๋“œ์—์„œ ์‚ดํŽด๋ณด๋ฉด ํŒŒ์ผ์„ ์ฝ์–ด์™€์„œ ๊ณ ์–‘์ด ์ด๋ฆ„๋“ค์„ ๋ฐฐ์—ด์— ๋‹ด์•„, ํ•ด๋‹น ์ด๋ฆ„๋“ค ์ค‘ ๋žœ๋ค์œผ๋กœ ํ•˜๋‚˜๋ฅผ ํ…์ŠคํŠธ๋กœ ๋ณด์—ฌ์ค€๋‹ค.

์ „์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์™€ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋žœ๋ค ํ•˜๊ฒŒ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ํ•„์š” ์—†์ด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„œ๋ฒ„์—์„œ ๋ฐ”๋กœ ํ•˜๋‚˜๋งŒ ๊ณจ๋ผ์„œ ๋ณด๋‚ด์ฃผ๋ฉด ๋œ๋‹ค.

import {readFile} from 'fs/promises';
import { readFile } from 'fs/promises';

async function server(url) {
  if (url === '/') {
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    // โœจ ๋ณ€๊ฒฝ
    const index = Math.floor(Math.random() * catNames.length);
    const catName = catNames[index];
    const json = {catName};
    return `<!doctype html>
    <html>
      <head>
        <link rel="stylesheet" href="/style.css" />
      </head>
      <body>
      	<script>
            function onClick(){
                // โœจ ๋ณ€๊ฒฝ
                const {catNames} = ${JSON.stringify(json)};
                document.body.innerText = catName;
            }
        </script>
        <button onClick="onClick()">Reveal</button>
      </body>
    </html>
    `;
  }
}

 

์ด์ œ๋Š” ์‘๋‹ต์œผ๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ํ•„์š”๋กœ ํ–ˆ๋˜ ๋žœ๋ค ํ•œ ๊ณ ์–‘์ด ์ด๋ฆ„ ํ•˜๋‚˜๋ฟ์ด๋‹ค.

 

1. ํ•˜๋‚˜์˜ ์ปดํ“จํ„ฐ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฌผ์„ ๋งŒ๋“ค์–ด๋‚ด๊ณ ,

import {readFile} from 'fs/promises';
const catFile = await readFile('./cats.txt', 'utf8');
const catNames = catFile.split('\n');
const index = Math.floor(Math.random() * catNames.length);
const catName = catNames[index];
const json = {catName};
return `<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
    <script>
        function onClick(){
            // โœจ ๋ณ€๊ฒฝ
            const {catNames} = ${JSON.stringify(json)};
            document.body.innerText = catName;
        }
    </script>
    <button onClick="onClick()">Reveal</button>
  </body>
</html>
`;

 

2. ์ดํ›„ ๋˜ ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ๋ณด๋‚ด์ง€๊ฒŒ ๋œ๋‹ค.

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
    <script>
        function onClick(){
            const {catNames} = ${JSON.stringify(json)};
            document.body.innerText = catName;
        }
    </script>
    <button onClick="onClick()">Reveal</button>
  </body>
</html>

 

1๊ณผ 2๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ์„ธ๊ณ„์—์„œ ์‹คํ–‰๋˜๊ณ , ์ด ๊ณผ์ •์€ ์ ‘๊ทผ๋ฒ•๊ณผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ƒ๊ด€์—†์ด ๋™์ผํ•œ ํ˜•ํƒœ์ด๋‹ค.

ํ•˜์ง€๋งŒ ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค๋ฉด syntax highlight๋„ ์ง€์›๋˜์ง€ ์•Š๊ณ , ๋ชจ๋“ˆ์ด๋‚˜ ํƒ€์ž… ์ฒดํฌ์˜ ํ˜œํƒ๋„ ๋ˆ„๋ฆฌ์ง€ ๋ชปํ•œ๋‹ค.

์ง€๊ธˆ์€ ๋‹จ์ˆœํ•œ ์ฝ”๋“œ์ง€๋งŒ ํ•ด๋‹น ์ฝ”๋“œ์— ๊ธฐ๋Šฅํ•˜๋‚˜ feature ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ๋ณต์žกํ•ด์งˆ ๊ฑฐ๋ผ๋Š” ๊บผ๋ฆผ์น™ํ•œ ๋Š๋‚Œ๋„ ๋“ ๋‹ค.

 

์œ„์˜ ์ฝ”๋“œ ๋ฉ์–ด๋ฆฌ๋ฅผ split ํ•  ์ˆ˜ ์—†์„๊นŒ?

๊ฐ๊ฐ์˜ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ๊ฐ ํ•จ์ˆ˜์— feature์— ๋งž๋Š” ์ด๋ฆ„์„ ๋ถ™์—ฌ์ฃผ๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ์ฝ”๋“œ๋Š” ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์งˆ ๊ฑฐ ๊ฐ™๋‹ค.

๋ฆฌ์•กํŠธ๋ฅผ ์จ๋ณธ ์ ์ด ์žˆ๋‹ค๋ฉด component๋ฅผ ์‰ฝ๊ฒŒ ๋– ์˜ฌ๋ฆด ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ปดํฌ๋„ŒํŠธ์˜ ์ธก๋ฉด์—์„œ ๋‹ค์‹œ ์งœ๋ณด์ž.

 

๋จผ์ € ๊ณ ์–‘์ด ์ด๋ฆ„์„ ์ƒ์„ฑํ•  ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์Œ์˜ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ์ด๋‹ค.

import {readFile} from 'fs/promises';
export default async function CatNameGenerator(){
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const index = Math.floor(Math.random() * catNames.length);
    const catName = catNames[index];
    // ...
}

 

์ผ๋‹จ 1์—์„œ ๋ฝ‘์•„์™”๋˜ ์ฝ”๋“œ๋ฅผ ์ œ์™ธํ•˜๊ณ  ํ•„์š”ํ•  ๊ฑฐ ๊ฐ™์€ ๋ถ€๋ถ„๋“ค์„ ์‚ดํŽด๋ณด์ž.

ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•  ๋•Œ ์ด๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™”๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด catName์„ onClick๋ฐ–์œผ๋กœ ๋นผ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

// ...์ค‘๋žต...
<script>
    // โœจ ๋ณ€๊ฒฝ
    const {catNames} = ${JSON.stringify(json)};
    function onClick(){
        document.body.innerText = catName;
    }
</script>
<button onClick="onClick()">Reveal</button>
// ...์ค‘๋žต...

 

์—ฌ๊ธฐ์„œ {catNames}๊ฐ€ ๋ฆฌ์•กํŠธ์—์„œ ์ต์ˆ™ํ•œ ํ˜•ํƒœ์ธ props๋ฅผ ๋„˜๊ฒจ๋ฐ›๋Š” ์ปดํฌ๋„ŒํŠธ์™€ ๋น„์Šทํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค.

import {readFile} from 'fs/promises';
export default async function CatNameGenerator(){
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const index = Math.floor(Math.random() * catNames.length);
    const catName = catNames[index];
    // ...
}

// โœจ ์ถ”๊ฐ€
function RevealButton({catName}){
    function onClick(){
        document.body.innerText = catName;
    }
    return (
    	<button onClick={onClick()}>
        	Reveal
        </button>
    );
}

 

โš ๏ธ html์ด ์•„๋‹Œ jsx์ด๋ฏ€๋กœ onClick()๋ฅผ ์ค‘๊ด„ํ˜ธ๋กœ ๊ฐ์‹ธ์ค˜์•ผ ํ•œ๋‹ค.

์ด์ œ ์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ค„ ์ปดํฌ๋„ŒํŠธ RevealButton์„ ๋ฆฌํ„ดํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊ธฐ๋Š” ์ž‘์—…์€ ๋๋‚œ ๊ฑฐ ๊ฐ™๋‹ค.

import {readFile} from 'fs/promises';
export default async function CatNameGenerator(){
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const index = Math.floor(Math.random() * catNames.length);
    const catName = catNames[index];
    // โœจ ์ถ”๊ฐ€
    return <RevealButton catName={catName}/>;
}

function RevealButton({catName}){
    function onClick(){
        document.body.innerText = catName;
    }
    return (
    	<button onClick={onClick()}>
        	Reveal
        </button>
    );
}

 

'๋ชจ๋‘ ๋น ์ง์—†์ด ์˜ฎ๊ฒจ๋†จ๋‚˜'์‹ถ์ง€๋งŒ ํ•œ ๊ฐ€์ง€ ๊ฑธ๋ฆฌ๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค. ์ด ๋ถ€๋ถ„์„ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ๋‚˜?

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
 // ...์ค‘๋žต...
  </body>
</html>

 

ํ† ํฌ ์ค€๋น„๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” Dan๊ณผ ํ˜„์žฌ ๋ฐœํ‘œ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” Dan์ด ๊ฐ™์€ ์‹œ๊ณต๊ฐ„์— ์กด์žฌํ•  ์ˆ˜ ์—†๋“ฏ์ด, 

์œ„์—์„œ ์ž‘์„ฑํ–ˆ๋˜ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋Š” ํ•˜๋‚˜๋กœ ์กด์žฌํ•  ์ˆ˜ ์—†๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜๊ณ , ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ๊ฐ„์— ์ž‘๋™ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

 

์ฆ‰, ์•„๋ž˜์˜ ์ฝ”๋“œ๊ฐ€ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋Š” ์„ธ๊ณ„์™€ 

import {readFile} from 'fs/promises';

export default async function CatNameGenerator(){
    const catFile = await readFile('./cats.txt', 'utf8');
    const catNames = catFile.split('\n');
    const index = Math.floor(Math.random() * catNames.length);
    const catName = catNames[index];
    return <RevealButton catName={catName}/>;
}

 

์•„๋ž˜์˜ ์ฝ”๋“œ๊ฐ€ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋Š” ์„ธ๊ณ„๋Š” ์„œ๋กœ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค.

function RevealButton({catName}){
    function onClick(){
        document.body.innerText = catName;
    }
    return (
    	<button onClick={onClick()}>
        	Reveal
        </button>
    );
}

 

์™ผ์ชฝ ์ฝ”๋“œ๋Š” ์„œ๋ฒ„์—์„œ ๋Œ์•„๊ฐ€๋Š” ์ฝ”๋“œ์ด๊ณ , ์„œ๋ฒ„์—์„œ import ๋˜๋Š” ๊ฒƒ๋“ค์€ ์„œ๋ฒ„์— ์กด์žฌํ•˜๋Š” ๊ฒƒ๋“ค์ด๊ณ ,

์˜ค๋ฅธ์ชฝ์˜ ์ฝ”๋“œ๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋Œ์•„๊ฐ€๋Š” ์ฝ”๋“œ์ด๋ฏ€๋กœ, ๋ธŒ๋ผ์šฐ์ €์—์„œ import ๋˜๋Š” ๊ฒƒ๋“ค์€ ๋ธŒ๋ผ์šฐ์ €์— ์กด์žฌํ•œ๋‹ค.

 

์ด ๋‘˜ ์‚ฌ์ด์— ์ •๋ณด๋Š” ์–ด๋–ป๊ฒŒ ์ฃผ๊ณ ๋ฐ›๊ฒŒ ๋˜๋Š” ๊ฑธ๊นŒ?

 

์ด์ „์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด html์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ด string์œผ๋กœ ์ „๋‹ฌ๋  ๋•Œ, JSON.stringify๋กœ ํ•จ๊ป˜ ๋ณด๋‚ด์ง„๋‹ค.

`<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
    <script>
        function onClick(){
            const {catNames} = ${JSON.stringify(json)};
            document.body.innerText = catName;
        }
    </script>
    <button onClick="onClick()">Reveal</button>
  </body>
</html>
`

 

๊ทธ๋Ÿผ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ์„ธ๊ณ„(ํ”„๋กœ๊ทธ๋žจ)๊ฐ€ ์žˆ๊ณ , ์ด ๋‘ ์„ธ๊ณ„ ๊ฐ„์— ํ•œ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๋ฌธ(door)์ด ์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ?

๊ณผ๊ฑฐ๋กœ๋ถ€ํ„ฐ ๋ฏธ๋ž˜์— ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋ฉด? ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋ฌด์–ธ๊ฐ€๊ฐ€ serialize ๊ฐ€๋Šฅํ•œ text๋‚˜ json์ด๋ผ๋ฉด?

 

๊ทธ ๋ฌธ์„ ํ•˜๋‚˜ ๋‹ฌ์•„๋ณด์ž.

// โœจ ์ถ”๊ฐ€
'use client';

function RevealButton({catName}){
    function onClick(){
        document.body.innerText = catName;
    }
    return (
    	<button onClick={onClick()}>
        	Reveal
        </button>
    );
}

 

Dan์€ next๋กœ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์ง€๋งŒ, ๋ฆฌ์•กํŠธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์›ํ•œ๋‹ค๋ฉด ์–ด๋–ค ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋„ ๋Œ์•„๊ฐ„๋‹ค.

๊ฐ™์€ ๋™์ž‘์„ ํ•˜๋Š”์ง€ ํ™•์ธ์„ ํ•˜์ž๋ฉด, rsc payload์— ํ•จ๊ป˜ ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ด ํŽด๋ฉด ๋žœ๋ค ํ•œ ๊ณ ์–‘์ด ์ด๋ฆ„ ํ•˜๋‚˜๊ฐ€ ํŽ˜์ด์ง€์™€ ํ•จ๊ป˜ ๋‚ด๋ ค์ง„๋‹ค๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

์ •๋ฆฌํ•˜์ž๋ฉด, ์šฐ๋ฆฌ๋Š” ์ข…์ข… ์„œ๋ฒ„์™€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ณ„๊ฐœ์˜ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ธ์‹ํ•œ๋‹ค. 

์›นํŽ˜์ด์ง€ UI๋ฅผ ๋žœ๋” ํ•  ๋•Œ๋„ ๋‘ ๊ฐœ์˜ ์ปดํ“จํ„ฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์™ผ์ชฝ ๋ฐ”๋‹๋ผ js์˜ ๊ฒฝ์šฐ return๋ฌธ ์ด์ „๊นŒ์ง€ ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๊ณ , ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹คํ–‰๋  ํ”„๋กœ๊ทธ๋žจ์„  return ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  JSON.stringify๋กœ ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ค„ ๋ฌธ์ด ์กด์žฌํ•œ๋‹ค๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์˜ค๋ฅธ์ชฝ ๋ฆฌ์•กํŠธ ๋ฒ„์ „์˜ ๊ฒฝ์šฐ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์ธ CatNameGenerator์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๊ณ ,

'use client' ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ๋ฐ›์„ ๋ฌธ์„  ๋šซ์–ด์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

ํ•ด๋‹น ์ง€์‹œ์–ด๋กœ ์ด ๋ชจ๋“ˆ์€ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ํ”„๋กญ์Šค๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•˜๋Š” ๊ฒƒ์ด๋‹ค.


๐Ÿ€ ๋งˆ์น˜๋ฉด์„œ

"use client"๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ๊ฐ„๊ฒฐํ•˜๊ณ  ์‰ฝ๊ฒŒ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ๋ณด์—ฌ์ฃผ๋Š” ํ† ํฌ์˜€๋˜ ๊ฑฐ ๊ฐ™๋‹ค. 
๊ทธ๋ฆฌ๊ณ  ๋ฐ”๋‹๋ผ js๋กœ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ์„์ง€๋ฅผ ๋ณด์—ฌ์ค˜์„œ 'use client'์˜ ์—ญํ• ์ด ๋” ์™€๋‹ฟ์•˜๋‹ค.
์˜๋ฌธ์œผ๋กœ ๋œ ํ† ํฌ์ง€๋งŒ ์–ด๋ ค์šด ๋‚ด์šฉ์ด ์•„๋‹ˆ๋ฏ€๋กœ ๊ผญ ์›๋ณธ ํ† ํฌ๋ฅผ ๋ณด๋Ÿฌ ๊ฐ€๋ฉด ์ข‹์„ ๊ฑฐ ๊ฐ™๋‹ค.

ํฌ์ŠคํŒ…์„ ๋ง‰ ์‹œ์ž‘ํ•˜๋˜ ์‹œ์ ์—์„œ ์ œ๋ชฉ์ธ React for Two Computers๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฒˆ์—ญํ•˜๋ฉด ์ข‹์„์ง€ ๊ณ ๋ฏผ์ด ๋˜์—ˆ๋‹ค.
์ง์—ญํ•˜๋ฉด '๋ฆฌ์•กํŠธ๋ฅผ ์œ„ํ•œ ๋‘ ๊ฐœ์˜ ์ปดํ“จํ„ฐ'์ธ๋ฐ ์ปดํ“จํ„ฐ๊ฐ€ ๋ฌด์—‡์„ ์œ„ํ•ด ๋‘ ๋Œ€ ์ธ์ง€ ์œ ์ถ”ํ•˜๊ธฐ ์–ด๋ ค์›Œ, ํ† ํฌ์˜ ๋‚ด์šฉ์„ ์ž˜ ๋‹ด์€ ์ œ๋ชฉ์€ ์•„๋‹Œ ๊ฒƒ ๊ฐ™์•˜๋‹ค.
๊ทธ๋ž˜์„œ '๋‘ ๋Œ€์˜ ์ปดํ“จํ„ฐ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ฆฌ์•กํŠธ'๋ผ๊ณ  ์˜์—ญ์„ ํ–ˆ๋Š”๋ฐ, ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„์˜ ์ฝ”๋“œ๊ฐ€ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” ํ•˜๋‚˜์˜ ์ปดํ“จํ„ฐ (๋ฆฌ์•กํŠธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ)์™€, ํด๋ผ์ด์–ธํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” ๋˜ ํ•˜๋‚˜์˜ ์ปดํ“จํ„ฐ(ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ)๋กœ ๋Œ์•„๊ฐ€์•ผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ณด์—ฌ์ฃผ๋Š” ํ”„๋กœ์„ธ์Šค๊ฐ€ ์™„์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์žฌ๋ฏธ์žˆ๋Š” ํ† ํฌ๋“ค์ด ์žˆ๋Š” react conf 2024์˜ ๋‹ค๋ฅธ ๋‚ด์šฉ๋“ค๋„ ์ฐจ์ฐจ ๋‹ค๋ค„๋ณด๊ณ ์ž ํ•œ๋‹ค.

๐Ÿ“š References

https://www.youtube.com/watch?v=ozI4V_29fj4