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

Front-end

React Server Component๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 

React Server Component๋ž€?

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ(Server Components)๋Š” ์ƒˆ๋กœ์šด ์œ ํ˜•์˜ ์ปดํฌ๋„ŒํŠธ๋กœ, ๋ฒˆ๋“ค๋ง ์ „์— ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง๋˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ SSR ์„œ๋ฒ„์™€๋Š” ๋ณ„๋„์˜ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.์ด ๋ณ„๋„์˜ ํ™˜๊ฒฝ์ด React ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋งํ•˜๋Š” "์„œ๋ฒ„"์ž…๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋นŒ๋“œ ์‹œ CI ์„œ๋ฒ„์—์„œ ํ•œ ๋ฒˆ ์‹คํ–‰๋˜๊ฑฐ๋‚˜, ๊ฐ ์š”์ฒญ๋งˆ๋‹ค ์›น ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ

์—ฌ๊ธฐ์„œ CI ์„œ๋ฒ„๋ž€?

CI ์„œ๋ฒ„๋ž€ Continuous Integration(์ง€์†์  ํ†ตํ•ฉ)์˜ ์•ฝ์ž๋กœ, ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์—์„œ ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ๋นŒ๋“œํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•œ ์„œ๋ฒ„๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. CI ์„œ๋ฒ„๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์ด๋ฅผ ์ €์žฅ์†Œ์— ํ‘ธ์‹œํ•  ๋•Œ, ๋ณ€๊ฒฝ๋œ ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ

  1. ๋นŒ๋“œ (์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•˜๊ฑฐ๋‚˜ ๋ฒˆ๋“ค๋ง)
  2. ํ…Œ์ŠคํŠธ (์œ ๋‹› ํ…Œ์ŠคํŠธ, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ๋“ฑ ์‹คํ–‰)
  3. ๋ฐฐํฌ ์ค€๋น„

๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ฝ”๋“œ ํ’ˆ์งˆ์„ ์œ ์ง€ํ•˜๊ณ  ๋ฌธ์ œ๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

React Server Components์˜ ๊ฒฝ์šฐ, CI ์„œ๋ฒ„์—์„œ ๋นŒ๋“œ ํƒ€์ž„์— ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹คํ–‰ํ•ด HTML์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜, ์ •์  ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉ์ž ์š”์ฒญ์— ๋”ฐ๋ผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋นŒ๋“œ ๋‹จ๊ณ„์—์„œ ๋ฏธ๋ฆฌ ์ฒ˜๋ฆฌ๋œ๋‹ค๋Š” ์ ์—์„œ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

 

∴ CI ์„œ๋ฒ„๋Š” ๊ฐœ๋ฐœ ์ž๋™ํ™” ๋„๊ตฌ๋กœ, React ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋นŒ๋“œ ์‹œ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค.

 

๊ณต์‹ ๋ฌธ์„œ์—์„œ๋Š” ์•„๋ž˜ 4๊ฐ€์ง€ ์ฑ•ํ„ฐ๋ฅผ ํ†ตํ•ด React Server Component๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

 

  • ์›น ์„œ๋ฒ„ ์—†๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ
  • ์›น ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ
  • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์— ์ƒํ˜ธ์ž‘์šฉ ์ถ”๊ฐ€ํ•˜๊ธฐ
  • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ

 

 


๋‚ด์šฉ์ด ๋„ˆ๋ฌด ๊ธธ๊ณ  ๋ณต์žกํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ธฐ ์ „ ๋จผ์ € ํ•ต์‹ฌ๋งŒ ์š”์•ฝํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €๋กœ ์ „์†ก๋˜์ง€ ์•Š๊ณ , ์„œ๋ฒ„์—์„œ๋งŒ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
    • ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๋กœ๋Š” HTML๋งŒ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.
  2. ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์™€ ์กฐํ•ฉ
    • ์ƒํ˜ธ์ž‘์šฉ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, "use client" ์ง€์‹œ์–ด๋กœ ์ •์˜๋œ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์™€ ์กฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ props๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  3. ๋น„๋™๊ธฐ ์ง€์›
    • async/await ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” ์„œ๋ฒ„์—์„œ awaitํ•˜๊ณ , ๋œ ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ use API๋กœ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
  4. ์„ฑ๋Šฅ ์ตœ์ ํ™”
    • ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•ด ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ณ , ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.
    • ์ŠคํŠธ๋ฆฌ๋ฐ๊ณผ Suspense๋ฅผ ํ†ตํ•ด ์ค‘์š”ํ•œ ์ฝ˜ํ…์ธ ๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ๋ Œ๋”๋งํ•˜๊ณ , ๋‚˜๋จธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  5. ์œ ์—ฐํ•œ ์•„ํ‚คํ…์ฒ˜
    • ์„œ๋ฒ„ ์ค‘์‹ฌ ๋ฉ€ํ‹ฐ ํŽ˜์ด์ง€ ์•ฑ(MPA)๊ณผ ํด๋ผ์ด์–ธํŠธ ์ค‘์‹ฌ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์•ฑ(SPA)์˜ ์žฅ์ ์„ ๊ฒฐํ•ฉํ•œ ์•„ํ‚คํ…์ฒ˜๋กœ, ๋™์ ์ด๊ณ  ์ƒํ˜ธ์ž‘์šฉ์ ์ธ ์•ฑ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

์›น ์„œ๋ฒ„ ์—†๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ

 

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋นŒ๋“œ ์‹œ ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์ •์  ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์›น ์„œ๋ฒ„๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์ฝ˜ํ…์ธ  ๊ด€๋ฆฌ ์‹œ์Šคํ…œ(CMS)์—์„œ ์ •์  ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์—์„œ Effect๋ฅผ ์‚ฌ์šฉํ•ด ์ •์  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค:

// bundle.js
import marked from 'marked'; // 35.9K (11.2K gzipped)
import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)

function Page({page}) {
  const [content, setContent] = useState('');
  // ์ฒซ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ์ดํ›„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  useEffect(() => {
    fetch(`/api/content/${page}`).then((data) => {
      setContent(data.content);
    });
  }, [page]);
  
  return <div>{sanitizeHtml(marked(content))}</div>;
}

// api.js
app.get(`/api/content/:page`, async (req, res) => {
  const page = req.params.page;
  const content = await file.readFile(`${page}.md`);
  res.send({content});
});

์ด ํŒจํ„ด์—์„œ๋Š” ์ •์  ์ฝ˜ํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ถ”๊ฐ€๋กœ 75KB(gzipped)์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ํŒŒ์‹ฑํ•ด์•ผ ํ•˜๊ณ ,

ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋œ ํ›„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์„ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ฝ˜ํ…์ธ ๋Š” ํŽ˜์ด์ง€์˜ ์ˆ˜๋ช… ๋™์•ˆ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ์ •์  ์ฝ˜ํ…์ธ ์ž…๋‹ˆ๋‹ค.

 

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋นŒ๋“œ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์ด๋Ÿฌํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import marked from 'marked'; // ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š์Œ
import sanitizeHtml from 'sanitize-html'; // ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š์Œ

async function Page({page}) {
  // ์•ฑ์ด ๋นŒ๋“œ๋  ๋•Œ ๋ Œ๋”๋ง ์ค‘ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
  const content = await file.readFile(`${page}.md`);
  
  return <div>{sanitizeHtml(marked(content))}</div>;
}

 

๋ Œ๋”๋ง๋œ ์ถœ๋ ฅ์€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR)์„ ํ†ตํ•ด HTML๋กœ ๋ณ€ํ™˜๋˜์–ด CDN์— ์—…๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.

์•ฑ์ด ๋กœ๋“œ๋  ๋•Œ, ํด๋ผ์ด์–ธํŠธ๋Š” ์›๋ž˜์˜ Page ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋งˆํฌ๋‹ค์šด์„ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•œ ๋ฌด๊ฑฐ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๊ณ , ๋ Œ๋”๋ง๋œ ์ถœ๋ ฅ๋งŒ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

<div><!-- ๋งˆํฌ๋‹ค์šด์˜ HTML ์ถœ๋ ฅ --></div>

 

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

  • ์ฒซ ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ์ฝ˜ํ…์ธ ๊ฐ€ ๋ฐ”๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  • ์ •์  ์ฝ˜ํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ฌด๊ฑฐ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์›น ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ํŽ˜์ด์ง€ ์š”์ฒญ ์‹œ ์›น ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด API๋ฅผ ๋”ฐ๋กœ ๊ตฌ์ถ•ํ•˜์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ ๊ณ„์ธต์— ์ง์ ‘ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฒˆ๋“ค๋ง๋˜๊ธฐ ์ „์— ๋ Œ๋”๋ง๋˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ์ดํ„ฐ์™€ JSX๋ฅผ props๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์—์„œ Effect๋ฅผ ์‚ฌ์šฉํ•ด ๋™์  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค:

// bundle.js
function Note({id}) {
  const [note, setNote] = useState('');
  // ์ฒซ ๋ Œ๋”๋ง ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  useEffect(() => {
    fetch(`/api/notes/${id}`).then(data => {
      setNote(data.note);
    });
  }, [id]);
  
  return (
    <div>
      <Author id={note.authorId} />
      <p>{note}</p>
    </div>
  );
}

function Author({id}) {
  const [author, setAuthor] = useState('');
  // Note๊ฐ€ ๋ Œ๋”๋ง๋œ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  // ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ๊ฐ„์˜ ๋А๋ฆฐ ์›Œํ„ฐํด(waterfall) ํ˜ธ์ถœ์„ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.
  useEffect(() => {
    fetch(`/api/authors/${id}`).then(data => {
      setAuthor(data.author);
    });
  }, [id]);

  return <span>By: {author.name}</span>;
}

// api
import db from './database';

app.get(`/api/notes/:id`, async (req, res) => {
  const note = await db.notes.get(id);
  res.send({note});
});

app.get(`/api/authors/:id`, async (req, res) => {
  const author = await db.authors.get(id);
  res.send({author});
});

 

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import db from './database';

async function Note({id}) {
  // ๋ Œ๋”๋ง ์ค‘ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  const note = await db.notes.get(id);
  return (
    <div>
      <Author id={note.authorId} />
      <p>{note}</p>
    </div>
  );
}

async function Author({id}) {
  // Note ์ดํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  // ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทผ์ฒ˜์— ์žˆ์œผ๋ฉด ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.
  const author = await db.authors.get(id);
  return <span>By: {author.name}</span>;
}

 

๋ฒˆ๋“ค๋Ÿฌ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐํ•ฉํ•˜๊ณ , ๋ Œ๋”๋ง๋œ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ ๋™์  ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•จ๊ป˜ ๋ฒˆ๋“ค๋กœ ๋ฌถ์Šต๋‹ˆ๋‹ค.

์„ ํƒ์ ์œผ๋กœ ์ด ๋ฒˆ๋“ค์€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR) ๋˜์–ด ํŽ˜์ด์ง€์˜ ์ดˆ๊ธฐ HTML์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋  ๋•Œ ๋ธŒ๋ผ์šฐ์ €๋Š” ์›๋ž˜์˜ Note์™€ Author ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์ง€ ์•Š๊ณ , ๋ Œ๋”๋ง๋œ ์ถœ๋ ฅ๋งŒ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

<div>
  <span>By: The React Team</span>
  <p>React 19 is...</p>
</div>

 

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์™€ ๋™์ ์œผ๋กœ ๋ Œ๋”๋ง๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์ด ์ƒˆ๋กœ์šด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„ํ‚คํ…์ฒ˜๋Š” ์„œ๋ฒ„ ์ค‘์‹ฌ ๋‹ค์ค‘ ํŽ˜์ด์ง€ ์•ฑ(Multi-Page Apps)์˜ ๊ฐ„๋‹จํ•œ "์š”์ฒญ/์‘๋‹ต" ๋ชจ๋ธ๊ณผ ํด๋ผ์ด์–ธํŠธ ์ค‘์‹ฌ ๋‹จ์ผ ํŽ˜์ด์ง€ ์•ฑ(Single-Page Apps)์˜ ๋งค๋„๋Ÿฌ์šด ์ƒํ˜ธ์ž‘์šฉ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ๋‘ ๋ Œ๋”๋ง ๋ฐฉ์‹์˜ ์žฅ์ ์„ ๋ชจ๋‘ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์— ์ƒํ˜ธ์ž‘์šฉ ์ถ”๊ฐ€ํ•˜๊ธฐ

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €๋กœ ์ „์†ก๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, useState์™€ ๊ฐ™์€ ์ƒํ˜ธ์ž‘์šฉ API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์— ์ƒํ˜ธ์ž‘์šฉ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด "use client" ์ง€์‹œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์™€ ์กฐํ•ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—๋Š” ๋ณ„๋„์˜ ์ง€์‹œ์–ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
"use server" ์ง€์‹œ์–ด๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์„œ๋ฒ„ ํ•จ์ˆ˜(Server Functions) ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ๋ณ„๋„ ์ง€์‹œ์–ด๋Š” ์—†์œผ๋ฏ€๋กœ ํ˜ผ๋™ํ•˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•˜์„ธ์š”.

์ž์„ธํ•œ ๋‚ด์šฉ์€ Directives ๋ฌธ์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š” Notes ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด ํ™•์žฅ ์—ฌ๋ถ€๋ฅผ toggleํ•˜๋Š” Expandable ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ

import Expandable from './Expandable';

async function Notes() {
  const notes = await db.notes.getAll();
  return (
    <div>
      {notes.map(note => (
        <Expandable key={note.id}>
          <p note={note} />
        </Expandable>
      ))}
    </div>
  );
}

ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ

"use client";

export default function Expandable({children}) {
  const [expanded, setExpanded] = useState(false);
  return (
    <div>
      <button onClick={() => setExpanded(!expanded)}>
        Toggle
      </button>
      {expanded && children}
    </div>
  );
}

 

์ž‘๋™ ๋ฐฉ์‹

  1. Notes ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋จผ์ € ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
  2. ๋ฒˆ๋“ค๋Ÿฌ๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์ธ Expandable์„ ์œ„ํ•œ ๋ฒˆ๋“ค์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €์—์„œ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋œ ์ถœ๋ ฅ(props)์„ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

<head>
  <!-- ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„ํ•œ ๋ฒˆ๋“ค -->
  <script src="bundle.js"></script>
</head>
<body>
  <div>
    <Expandable key={1}>
      <p>this is the first note</p>
    </Expandable>
    <Expandable key={2}>
      <p>this is the second note</p>
    </Expandable>
    <!--...-->
  </div> 
</body>

 

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


์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” async/await ์„ ์‚ฌ์šฉํ•˜๋Š” ์ƒˆ๋กœ์šด ๋ฐฉ์‹์˜ ์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ์—์„œ await๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด React๋Š” ์ผ์‹œ ์ค‘๋‹จ(suspend)ํ•˜๊ณ , ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ ๋’ค ๋ Œ๋”๋ง์„ ์žฌ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฐฉ์‹์€ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฒฝ๊ณ„๋ฅผ ๋„˜๋‚˜๋“ค๋ฉฐ Suspense๋ฅผ ์œ„ํ•œ ์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์‹ฌ์ง€์–ด ์„œ๋ฒ„์—์„œ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑํ•œ ๋’ค, ํด๋ผ์ด์–ธํŠธ์—์„œ ์ด๋ฅผ awaitํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ

import db from './database';

async function Page({id}) {
  // ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ผ์‹œ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.
  const note = await db.notes.get(id);
  
  // ์—ฌ๊ธฐ์„œ๋Š” ๋Œ€๊ธฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋ฏธ์Šค๋Š” ์„œ๋ฒ„์—์„œ ์‹œ์ž‘๋˜๊ณ ,
  // ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
  const commentsPromise = db.comments.get(note.id);
  
  return (
    <div>
      {note}
      <Suspense fallback={<p>Loading Comments...</p>}>
        <Comments commentsPromise={commentsPromise} />
      </Suspense>
    </div>
  );
}

 

ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ

"use client";
import {use} from 'react';

function Comments({commentsPromise}) {
  // ์„œ๋ฒ„์—์„œ ์‹œ์ž‘๋œ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ด์–ด๋ฐ›์Šต๋‹ˆ๋‹ค.
  // ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ์ผ์‹œ ์ค‘๋‹จ(suspend)๋ฉ๋‹ˆ๋‹ค.
  const comments = use(commentsPromise);
  return comments.map(comment => <p>{comment}</p>);
}

 

 

์ž‘๋™ ๋ฐฉ์‹

  • note ์ฝ˜ํ…์ธ ๋Š” ํŽ˜์ด์ง€ ๋ Œ๋”๋ง์— ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ, ์„œ๋ฒ„์—์„œ ์ด๋ฅผ await ํ•ฉ๋‹ˆ๋‹ค.
  • ๋Œ“๊ธ€์€ ํŽ˜์ด์ง€ ํ•˜๋‹จ ์ฝ˜ํ…์ธ ๋กœ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ๊ธฐ ๋•Œ๋ฌธ์—, ์„œ๋ฒ„์—์„œ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์‹œ์ž‘ํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ use API๋ฅผ ์‚ฌ์šฉํ•ด ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์—์„œ ์ด ์ž‘์—…์€ ์ผ์‹œ ์ค‘๋‹จ(suspend)๋˜์ง€๋งŒ, ํŽ˜์ด์ง€์˜ note ์ฝ˜ํ…์ธ  ๋ Œ๋”๋ง์„ ๋ง‰์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ

ํด๋ผ์ด์–ธํŠธ์—์„œ ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ ์ง€์›

  • ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๋น„๋™๊ธฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง์ ‘ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ํด๋ผ์ด์–ธํŠธ์—์„œ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๊ธฐ๋‹ค๋ฆด ๋•Œ๋Š” use API๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ•˜๊ณ  ์ •๋ฆฌํ•˜๋ฉด์„œ Server Component๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ์ด์ ์ด ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์–ด๋–ค ์žฅ์ ์„ ์ œ๊ณตํ•˜๋Š”์ง€ ๋‹ค๋ฅธ ๊ด€์ ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๊ธ€์„ ์š”์•ฝํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 


1. ๋ฐ์ดํ„ฐ ํŽ˜์นญ ๋ฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์˜ ์šฉ์ด์„ฑ

React ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ์ดํ„ฐ ํŽ˜์นญ์„ ํ•˜๋ ค๋ฉด ๋ณดํ†ต ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ์™ธ๋ถ€ API์— ์ง์ ‘ ์š”์ฒญํ•˜๊ธฐ
  2. ์„œ๋ฒ„์— ๋‚ด๋ถ€ API ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ์— ์š”์ฒญํ•˜๊ธฐ

ํ•˜์ง€๋งŒ ์ด ๋‘ ๋ฐฉ๋ฒ•์€ ๊ฐ๊ฐ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

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

React Server Component์˜ ์žฅ์ 

React Server Component(RSC)๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์ค๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

async function getUserData() {
  // ๋ฐ์ดํ„ฐ ํŽ˜์นญ ๋กœ์ง ์ž‘์„ฑ
}

async function MyComponent() {
  let data = await getUserData();

  if (!data) {
    return <div className="error-msg">User not found!</div>;
  }

  return (
    <div>
      {data.username}
      <DeleteUserButton id={data.id} />
    </div>
  );
}

์ด ์˜ˆ์ œ์˜ ํŠน์ง•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ฝ”๋“œ๋‚˜ ๋ธŒ๋ผ์šฐ์ € API, ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋“ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ.
  • ์ƒํƒœ ๊ด€๋ฆฌ๋‚˜ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์—†์œผ๋ฉฐ, ๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  ๋ Œ๋”๋ง๋งŒ ํ•จ.
  • ๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ๋•Œ๋Š” ๋‹ค๋ฅธ HTML์„ ๋ฐ˜ํ™˜.
  • DeleteUserButton๊ณผ ๊ฐ™์€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์™€๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฒฐํ•ฉ ๊ฐ€๋Šฅ.

RSC์˜ ์ฃผ์š” ์ด์ 

  • ๋‚ด๋ถ€ API ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋ณ„๋„๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋จ.
  • ๋ฐ์ดํ„ฐ ์†Œ์Šค์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ UI ์ปดํฌ๋„ŒํŠธ์— ๊ฒฐํ•ฉํ•˜์ง€ ์•Š์Œ.
  • CORS ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ์™ธ๋ถ€ API, ๋กœ์ปฌ ํŒŒ์ผ ๋“ฑ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์†Œ์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ.

๋”ฐ๋ผ์„œ, RSC๋Š” ๋ฐ์ดํ„ฐ ํŽ˜์นญ์„ ๋” ๊ฐ„๋‹จํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

2. ๋” ๋น ๋ฅธ UI์™€ ๊ฐœ์„ ๋œ UX

  • ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•ด๋‹น DOM์„ ๊ทธ๋ฆด ๋•Œ ๋ณ„๋„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š” ์—†์Œ.
    • ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ HTML์„ DOM์— ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋จ.
  • ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ HTML์„ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  DOM์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ž‘์—…์ด ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋จ.
  • ํŠนํžˆ ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ”๊พธ๋ฉด ๋” ๋งŽ์€ ์ฒ˜๋ฆฌ ์ž‘์—…์„ ์„œ๋ฒ„๋กœ ๋„˜๊ฒจ, ํด๋ผ์ด์–ธํŠธ์˜ ๋ถ€ํ•˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Œ.
  • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…์ด ์ค„์–ด UI๊ฐ€ ๋” ๋นจ๋ฆฌ ๋กœ๋“œ๋˜๋ฉฐ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅธ ์ฒซ ํ™”๋ฉด ๋กœ๋“œ๋ฅผ ์ œ๊ณตํ•˜์—ฌ UX ๊ฐœ์„ ์— ๊ธฐ์—ฌ.

3. ๋” ๊ฐ„๋‹จํ•œ UI ์ฝ”๋“œ

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

 

 

 

 

  • references:
 

Server Components – React

The library for web and native user interfaces

react.dev

 

It’s 2024, you should be using React Server Components already

3 reasons why you should actually use RSC in all your projects

itnext.io