์ฃผ์˜ํ•˜์„ธ์š”!

renderToString์€ ์ŠคํŠธ๋ฆฌ๋ฐ์ด๋‚˜ ๋ฐ์ดํ„ฐ ๋Œ€๊ธฐ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์•ˆ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

renderToString์€ React ํŠธ๋ฆฌ๋ฅผ HTML ๋ฌธ์ž์—ด๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

const html = renderToString(reactNode)

๋ ˆํผ๋Ÿฐ์Šค

renderToString(reactNode)

์„œ๋ฒ„์—์„œ renderToString์„ ์‹คํ–‰ํ•˜๋ฉด ์•ฑ์„ HTML๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

import { renderToString } from 'react-dom/server';

const html = renderToString(<App />);

ํด๋ผ์ด์–ธํŠธ์—์„œ hydrateRoot์„ ํ˜ธ์ถœํ•˜๋ฉด ์„œ๋ฒ„์—์„œ ์ƒ์„ฑ๋œ HTML์„ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์•„๋ž˜์—์„œ ๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • reactNode: HTML๋กœ ๋ Œ๋”๋งํ•  React ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด <App />๊ณผ ๊ฐ™์€ JSX ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜

HTML ๋ฌธ์ž์—ด.

์ฃผ์˜์‚ฌํ•ญ

  • renderToString๋Š” Suspense ์ง€์›์— ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ค‘๋‹จ๋œ๋‹ค๋ฉด renderToString๋Š” ์ฆ‰์‹œ ํ•ด๋‹น ํด๋ฐฑ์„ HTML๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

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


์‚ฌ์šฉ๋ฒ•

React ํŠธ๋ฆฌ๋ฅผ HTML ๋ฌธ์ž์—ด๋กœ ๋ Œ๋”๋งํ•˜๊ธฐ

์„œ๋ฒ„ ์‘๋‹ต๊ณผ ํ•จ๊ป˜ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” HTML ๋ฌธ์ž์—ด๋กœ ์•ฑ์„ ๋ Œ๋”๋งํ•˜๋ ค๋ฉด renderToString์„ ํ˜ธ์ถœํ•˜์„ธ์š”:

import { renderToString } from 'react-dom/server';

// ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ ๊ตฌ๋ฌธ์€ ๋ฐฑ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค
app.use('/', (request, response) => {
const html = renderToString(<App />);
response.send(html);
});

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด React ์ปดํฌ๋„ŒํŠธ์˜ ์ดˆ๊ธฐ ๋น„๋Œ€ํ™”ํ˜• HTML ์ถœ๋ ฅ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„์—์„œ ์ƒ์„ฑ๋œ HTML์„ hydrateํ•˜์—ฌ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก hydrateRoot ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ํ•˜์„ธ์š”!

renderToString์€ ์ŠคํŠธ๋ฆฌ๋ฐ ๋˜๋Š” ๋ฐ์ดํ„ฐ ๋Œ€๊ธฐ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์•ˆ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.


๋Œ€์•ˆ

์„œ๋ฒ„์—์„œ renderToString์„ ์ŠคํŠธ๋ฆฌ๋ฐ ํ•จ์ˆ˜๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

renderToString์€ ๋ฌธ์ž์—ด์„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์ŠคํŠธ๋ฆฌ๋ฐ์ด๋‚˜ ๋ฐ์ดํ„ฐ ๋Œ€๊ธฐ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ€๋Šฅํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์™„์ „ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ๋Œ€์•ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค:

  • Node.js๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ [โ€˜renderToPipeableStreamโ€™]์„ ์‚ฌ์šฉํ•˜์„ธ์š”. (/reference/react-dom/server/renderToPipeableStream)
  • Deno์™€ ์ตœ์‹  ์—ฃ์ง€ ๋Ÿฐํƒ€์ž„์—์„œ Web Streams์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ renderToReadableStream ์„ ์‚ฌ์šฉํ•˜์„ธ์š”

์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ์ŠคํŠธ๋ฆผ์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋„ renderToString์„ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—์„œ renderToString ์ œ๊ฑฐํ•˜๊ธฐ

ํด๋ผ์ด์–ธํŠธ์—์„œ ์ผ๋ถ€ ์ปดํฌ๋„ŒํŠธ๋ฅผ HTML๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด renderToString์„ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

// ๐Ÿšฉ ๋ถˆํ•„์š”: ํด๋ผ์ด์–ธํŠธ์—์„œ renderToString ์‚ฌ์šฉํ•˜๊ธฐ
import { renderToString } from 'react-dom/server';

const html = renderToString(<MyIcon />);
console.log(html); // ์˜ˆ๋ฅผ ๋“ค์–ด, "<svg>...</svg>"

ํด๋ผ์ด์–ธํŠธ์—์„œ react-dom/server๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฒˆ๋“ค ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๋ฏ€๋กœ ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ผ๋ถ€ ์ปดํฌ๋„ŒํŠธ๋ฅผ HTML๋กœ ๋ Œ๋”๋งํ•ด์•ผ ํ•  ๊ฒฝ์šฐ createRoot์„ ์‚ฌ์šฉํ•˜๊ณ  DOM์—์„œ HTML์„ ์ฝ์œผ์„ธ์š”:

import { createRoot } from 'react-dom/client';
import { flushSync } from 'react-dom';

const div = document.createElement('div');
const root = createRoot(div);
flushSync(() => {
root.render(<MyIcon />);
});
console.log(div.innerHTML); // ์˜ˆ๋ฅผ ๋“ค์–ด, "<svg>...</svg>"

flushSync ํ˜ธ์ถœ์€ innerHTML ์†์„ฑ์„ ์ฝ๊ธฐ ์ „์— DOM์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


๋ฌธ์ œ ํ•ด๊ฒฐ

์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ผ์‹œ ์ค‘๋‹จ๋˜๋ฉด HTML์— ํ•ญ์ƒ ํด๋ฐฑ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

renderToString์€ Suspense๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ผ๋ถ€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ผ์‹œ ์ค‘๋‹จ๋˜๊ฑฐ๋‚˜ (์˜ˆ๋ฅผ ๋“ค์–ด, lazy์™€ ํ•จ๊ป˜ ์ •์˜๋˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ) renderToString์€ ์ฝ˜ํ…์ธ ๊ฐ€ ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. renderToString๋Š” ๊ทธ ์œ„์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด <Suspense> ๊ฒฝ๊ณ„๋ฅผ ์ฐพ์•„ fallback ํ”„๋กœํผํ‹ฐ๋ฅผ HTML์— ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ๋‚ด์šฉ์€ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๊ฐ€ ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

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