createRoot๋กœ ๋ธŒ๋ผ์šฐ์ € DOM ๋…ธ๋“œ ์•ˆ์— React ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const root = createRoot(domNode, options?)

๋ ˆํผ๋Ÿฐ์Šค

createRoot(domNode, options?)

createRoot๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ € DOM ์—˜๋ฆฌ๋จผํŠธ ์•ˆ์— ์ฝ˜ํ…์ธ ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” React ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

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

const domNode = document.getElementById('root');
const root = createRoot(domNode);

React๋Š” domNode์— ๋Œ€ํ•œ ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ทธ ์•ˆ์— ์žˆ๋Š” DOM์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•œ ํ›„์—๋Š” root.render๋ฅผ ํ˜ธ์ถœํ•ด ๊ทธ ์•ˆ์— React ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ‘œ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

root.render(<App />);

์˜จ์ „ํžˆ React๋งŒ์œผ๋กœ ์ž‘์„ฑ๋œ ์•ฑ์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ createRoot ํ˜ธ์ถœ์ด ํ•˜๋‚˜๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€์˜ ์ผ๋ถ€์— React๋ฅผ โ€œ๋ฟŒ๋ ค์„œโ€ ์‚ฌ์šฉํ•˜๋Š” ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ์—๋Š” ๋ฃจํŠธ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๋งŒํผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

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

  • domNode: DOM ์—˜๋ฆฌ๋จผํŠธ. React๋Š” DOM ์—˜๋ฆฌ๋จผํŠธ์— ๋Œ€ํ•œ ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ Œ๋”๋ง๋œ React ์ฝ˜ํ…์ธ ๋ฅผ ํ‘œ์‹œํ•˜๋Š” render์™€ ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ๋ฃจํŠธ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

  • optional options: React ๋ฃจํŠธ์— ๋Œ€ํ•œ ์˜ต์…˜์„ ๊ฐ€์ง„ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

    • optional onRecoverableError: React๊ฐ€ ์˜ค๋ฅ˜๋กœ๋ถ€ํ„ฐ ์ž๋™์œผ๋กœ ๋ณต๊ตฌ๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ.
    • optional identifierPrefix : React๊ฐ€ useId์— ์˜ํ•ด ์ƒ์„ฑ๋œ ID์— ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ์ž์—ด ์ ‘๋‘์‚ฌ. ๊ฐ™์€ ํŽ˜์ด์ง€์—์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ฃจํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ถฉ๋Œ์„ ํ”ผํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

createRoot๋Š” render์™€ unmount ๋‘ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

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

  • ์•ฑ์ด ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง ๋˜๋Š” ๊ฒฝ์šฐ createRoot()๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  hydrateRoot()๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ์•ฑ์— createRoot ํ˜ธ์ถœ์ด ๋‹จ ํ•˜๋‚˜๋งŒ ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ด ํ˜ธ์ถœ์„ ๋Œ€์‹  ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ์˜ ์ž์‹์ด ์•„๋‹Œ DOM ํŠธ๋ฆฌ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„(์˜ˆ: ๋ชจ๋‹ฌ ๋˜๋Š” ํˆดํŒ)์— JSX ์กฐ๊ฐ์„ ๋ Œ๋”๋งํ•˜๋ ค๋Š” ๊ฒฝ์šฐ, createRoot ๋Œ€์‹  createPortal์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

root.render(reactNode)

root.render๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ JSX์กฐ๊ฐ(โ€œReact ๋…ธ๋“œโ€)์„ React ๋ฃจํŠธ์˜ ๋ธŒ๋ผ์šฐ์ € DOM ๋…ธ๋“œ์— ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

root.render(<App />);

React๋Š” root์— <App />์„ ํ‘œ์‹œํ•˜๊ณ  ๊ทธ ์•ˆ์— ์žˆ๋Š” DOM์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

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

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

  • reactNode: ํ‘œ์‹œํ•˜๋ ค๋Š” React ๋…ธ๋“œ. ์ผ๋ฐ˜์ ์œผ๋กœ <App />๊ณผ ๊ฐ™์€ JSX ์กฐ๊ฐ์ด ๋˜์ง€๋งŒ, createElement()๋กœ ์ž‘์„ฑํ•œ React ์—˜๋ฆฌ๋จผํŠธ, ๋ฌธ์ž์—ด, ์ˆซ์ž, null, undefined ๋“ฑ์„ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

root.render๋Š” undefined๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

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

  • root.render๋ฅผ ์ฒ˜์Œ ํ˜ธ์ถœํ•˜๋ฉด React๋Š” React ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ธฐ ์ „์— React ๋ฃจํŠธ ๋‚ด๋ถ€์˜ ๋ชจ๋“  ๊ธฐ์กด HTML ์ฝ˜ํ…์ธ ๋ฅผ ์ง€์›๋‹ˆ๋‹ค.

  • ์„œ๋ฒ„์—์„œ ๋˜๋Š” ๋นŒ๋“œ ์ค‘์— React์— ์˜ํ•ด ์ƒ์„ฑ๋œ HTML์ด ๋ฃจํŠธ์˜ DOM ๋…ธ๋“œ์— ํฌํ•จ๋œ ๊ฒฝ์šฐ, ๋Œ€์‹  ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ธฐ์กด HTML์— ์ฒจ๋ถ€ํ•˜๋Š” hydrateRoot()๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • ๋™์ผํ•œ ๋ฃจํŠธ์—์„œ render๋ฅผ ๋‘ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•˜๋ฉด, React๋Š” ํ•„์š”์— ๋”ฐ๋ผ DOM์„ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ „๋‹ฌํ•œ ์ตœ์‹  JSX๋ฅผ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค. React๋Š” ์ด์ „์— ๋ Œ๋”๋ง ๋œ ํŠธ๋ฆฌ์™€ โ€œ๋น„๊ตโ€ํ•ด์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„๊ณผ ๋‹ค์‹œ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ๋ฃจํŠธ์—์„œ render๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ set ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. React๋Š” ๋ถˆํ•„์š”ํ•œ DOM ์—…๋ฐ์ดํŠธ๋ฅผ ํ”ผํ•ฉ๋‹ˆ๋‹ค.


root.unmount()

root.unmount๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด React ๋ฃจํŠธ ๋‚ด๋ถ€์—์„œ ๋ Œ๋”๋ง ๋œ ํŠธ๋ฆฌ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

root.unmount();

์˜จ์ „ํžˆ React๋งŒ์œผ๋กœ ์ž‘์„ฑ๋œ ์•ฑ์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ root.unmount์— ๋Œ€ํ•œ ํ˜ธ์ถœ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ด ํ•จ์ˆ˜๋Š” ์ฃผ๋กœ React ๋ฃจํŠธ์˜ DOM ๋…ธ๋“œ(๋˜๋Š” ๊ทธ ์กฐ์ƒ ๋…ธ๋“œ)๊ฐ€ ๋‹ค๋ฅธ ์ฝ”๋“œ์— ์˜ํ•ด DOM์—์„œ ์ œ๊ฑฐ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด DOM์—์„œ ๋น„ํ™œ์„ฑ ํƒญ์„ ์ œ๊ฑฐํ•˜๋Š” jQuery ํƒญ ํŒจ๋„์„ ์ƒ์ƒํ•ด ๋ณด์„ธ์š”. ํƒญ์ด ์ œ๊ฑฐ๋˜๋ฉด ๊ทธ ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ(๋‚ด๋ถ€์˜ React ๋ฃจํŠธ๋ฅผ ํฌํ•จ)์ด DOM์—์„œ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ root.unmount๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ œ๊ฑฐ๋œ ๋ฃจํŠธ์˜ ์ฝ˜ํ…์ธ  ๊ด€๋ฆฌ๋ฅผ โ€œ์ค‘์ง€โ€ํ•˜๋„๋ก React์— ์ง€์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ œ๊ฑฐ๋œ ๋ฃจํŠธ ๋‚ด๋ถ€์˜ ์ปดํฌ๋„ŒํŠธ๋Š” ๊ตฌ๋…๊ณผ ๊ฐ™์€ ์ „์—ญ ๋ฆฌ์†Œ์Šค๋ฅผ ์ •๋ฆฌํ•˜๊ณ  ํ™•๋ณดํ•˜๋Š” ๋ฒ•์„ ๋ชจ๋ฅด๋Š” ์ฑ„๋กœ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

root.unmount๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ฃจํŠธ์— ์žˆ๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ unmount ๋˜๊ณ , ํŠธ๋ฆฌ์ƒ์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋‚˜ state๊ฐ€ ์ œ๊ฑฐ๋˜๋ฉฐ, ๋ฃจํŠธ DOM ๋…ธ๋“œ์—์„œ React๊ฐ€ โ€œ๋ถ„๋ฆฌโ€๋ฉ๋‹ˆ๋‹ค.

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

root.unmount๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

root.unmount returns undefined.

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

  • root.unmount๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํŠธ๋ฆฌ์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ unmount ๋˜๊ณ  ๋ฃจํŠธ DOM ๋…ธ๋“œ์—์„œ React๊ฐ€ โ€œ๋ถ„๋ฆฌโ€๋ฉ๋‹ˆ๋‹ค.

  • root.unmount๋ฅผ ํ•œ ๋ฒˆ ํ˜ธ์ถœํ•œ ํ›„์—๋Š” ๊ฐ™์€ ๋ฃจํŠธ์—์„œ root.render๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. unmount ๋œ ๋ฃจํŠธ์—์„œ root.render๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๊ณ  ํ•˜๋ฉด โ€œunmount ๋œ root๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.โ€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•ด๋‹น ๋…ธ๋“œ์˜ ์ด์ „ ๋ฃจํŠธ๊ฐ€ unmount ๋œ ํ›„ ๋™์ผํ•œ DOM ๋…ธ๋“œ์— ์ƒˆ๋กœ์šด ๋ฃจํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋Š” ์žˆ์Šต๋‹ˆ๋‹ค.


์‚ฌ์šฉ๋ฒ•

์˜จ์ „ํžˆ React๋งŒ์œผ๋กœ ์ž‘์„ฑ๋œ ์•ฑ ๋ Œ๋”๋งํ•˜๊ธฐ

์•ฑ์ด ์˜จ์ „ํžˆ React๋งŒ์œผ๋กœ ์ž‘์„ฑ๋œ ๊ฒฝ์šฐ, ์ „์ฒด ์•ฑ์— ๋Œ€ํ•ด ๋‹จ์ผ ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.

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

const root = createRoot(document.getElementById('root'));
root.render(<App />);

์ผ๋ฐ˜์ ์œผ๋กœ ์ด ์ฝ”๋“œ๋Š” ์‹œ์ž‘ํ•  ๋•Œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  1. HTML์— ์ •์˜๋œ ๋ธŒ๋ผ์šฐ์ € DOM ๋…ธ๋“œ๋ฅผ ์ฐพ์œผ์„ธ์š”.
  2. ์•ฑ ๋‚ด๋ถ€์— React ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ‘œ์‹œํ•˜์„ธ์š”.
import { createRoot } from 'react-dom/client';
import App from './App.js';
import './styles.css';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

์•ฑ์ด ์˜จ์ „ํžˆ React๋งŒ์œผ๋กœ ์ž‘์„ฑ๋œ ๊ฒฝ์šฐ, ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฃจํŠธ๋ฅผ ๋” ๋งŒ๋“ค๊ฑฐ๋‚˜ root.render๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด ์‹œ์ ๋ถ€ํ„ฐ React๋Š” ์ „์ฒด ์•ฑ์˜ DOM์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋” ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด App ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์ค‘์ฒฉ์‹œํ‚ค์„ธ์š”. UI ์—…๋ฐ์ดํŠธ๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ state๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋‹ฌ์ด๋‚˜ ํˆดํŒ๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ์ฝ˜ํ…์ธ ๋ฅผ DOM ๋…ธ๋“œ ์™ธ๋ถ€์— ํ‘œ์‹œํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ portal๋กœ ๋ Œ๋”๋งํ•˜์„ธ์š”.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

HTML์ด ๋น„์–ด์žˆ์œผ๋ฉด, ์•ฑ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ๋กœ๋“œ๋˜๊ณ  ์‹คํ–‰๋  ๋•Œ๊นŒ์ง€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋นˆ ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

<div id="root"></div>

์ด๊ฒƒ์€ ๋งค์šฐ ๋Š๋ฆฌ๊ฒŒ ๋Š๊ปด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์—์„œ ๋˜๋Š” ๋นŒ๋“œ ์ค‘์— ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ดˆ๊ธฐ HTML์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ฐฉ๋ฌธ์ž๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „์— ํ…์ŠคํŠธ๋ฅผ ์ฝ๊ณ , ์ด๋ฏธ์ง€๋ฅผ ๋ณด๊ณ , ๋งํฌ๋ฅผ ํด๋ฆญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ตœ์ ํ™”๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์‹คํ–‰ ์‹œ์ ์— ๋”ฐ๋ผ ์ด๋ฅผ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง(SSR) ๋˜๋Š” ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ(SSG) ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

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

์„œ๋ฒ„ ๋ Œ๋”๋ง์ด๋‚˜ ์ •์  ์ƒ์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ์•ฑ์€ createRoot ๋Œ€์‹  hydrateRoot๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด React๋Š” DOM ๋…ธ๋“œ๋ฅผ ํŒŒ๊ดดํ•˜๊ณ  ๋‹ค์‹œ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹  HTML์œผ๋กœ๋ถ€ํ„ฐ hydrate(์žฌ์‚ฌ์šฉ)ํ•ฉ๋‹ˆ๋‹ค.


React๋กœ ๋ถ€๋ถ„์ ์œผ๋กœ ์ž‘์„ฑ๋œ ํŽ˜์ด์ง€ ๋ Œ๋”๋งํ•˜๊ธฐ

ํŽ˜์ด์ง€๊ฐ€ React๋งŒ์œผ๋กœ ์ž‘์„ฑ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, React๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ ์ตœ์ƒ์œ„ UI์— ๋Œ€ํ•œ ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด createRoot๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฃจํŠธ๋งˆ๋‹ค root.render๋ฅผ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ ๊ฐ๊ฐ ๋‹ค๋ฅธ ์ฝ˜ํ…์ธ ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๊ฐœ์˜ React ์ปดํฌ๋„ŒํŠธ๊ฐ€ index.html ํŒŒ์ผ์— ์ •์˜๋œ ๋‘ ๊ฐœ์˜ DOM ๋…ธ๋“œ์— ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

import './styles.css';
import { createRoot } from 'react-dom/client';
import { Comments, Navigation } from './Components.js';

const navDomNode = document.getElementById('navigation');
const navRoot = createRoot(navDomNode); 
navRoot.render(<Navigation />);

const commentDomNode = document.getElementById('comments');
const commentRoot = createRoot(commentDomNode); 
commentRoot.render(<Comments />);

document.createElement()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ DOM ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฌธ์„œ์— ์ˆ˜๋™์œผ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

const domNode = document.createElement('div');
const root = createRoot(domNode);
root.render(<Comment />);
document.body.appendChild(domNode); // You can add it anywhere in the document

DOM ๋…ธ๋“œ์—์„œ React ํŠธ๋ฆฌ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์ด ํŠธ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๋ฅผ ์ •๋ฆฌํ•˜๋ ค๋ฉด root.unmount๋ฅผ ํ˜ธ์ถœํ•˜์„ธ์š”.

root.unmount();

์ด ๊ธฐ๋Šฅ์€ React ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์ž‘์„ฑ๋œ ์•ฑ ๋‚ด๋ถ€์— ์žˆ๋Š” ๊ฒฝ์šฐ์— ์ฃผ๋กœ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.


Updating a root component

๊ฐ™์€ ๋ฃจํŠธ์—์„œ render๋ฅผ ๋‘ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ๊ตฌ์กฐ๊ฐ€ ์ด์ „ ๋ Œ๋”๋ง๊ณผ ์ผ์น˜ํ•˜๋Š” ํ•œ, React๋Š” ๊ธฐ์กด state๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ์—์„œ input์— ์–ด๋–ป๊ฒŒ ํƒ€์ดํ•‘ํ•˜๋“  ๊ด€๊ณ„์—†์ด, ๋งค ์ดˆ ๋ฐ˜๋ณต๋˜๋Š” render ํ˜ธ์ถœ๋กœ ์ธํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š์Œ์„ ์ฃผ๋ชฉํ•˜์„ธ์š”.

import { createRoot } from 'react-dom/client';
import './styles.css';
import App from './App.js';

const root = createRoot(document.getElementById('root'));

let i = 0;
setInterval(() => {
  root.render(<App counter={i} />);
  i++;
}, 1000);

render๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ํ”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ๋Š”, ์ปดํฌ๋„ŒํŠธ๊ฐ€ state๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.


๋ฌธ์ œ ํ•ด๊ฒฐ

๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ–ˆ๋Š”๋ฐ ์•„๋ฌด๊ฒƒ๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์‹ค์ œ๋กœ ์•ฑ์„ ๋ฃจํŠธ์— ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ์•Š์•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

import { createRoot } from 'react-dom/client';
import App from './App.js';

const root = createRoot(document.getElementById('root'));
root.render(<App />);

root.render(...) ๋ช…๋ น ์—†์ด๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


โ€œ๋Œ€์ƒ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ DOM ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹คโ€ ๋ผ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ค๋ฅ˜๋Š” createRoot์— ์ „๋‹ฌํ•œ ๊ฒƒ์ด DOM ๋…ธ๋“œ๊ฐ€ ์•„๋‹˜์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋ฌด์Šจ ์ผ์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š๋‹ค๋ฉด ๋กœ๊ทธ ์‚ดํŽด๋ณด๊ธฐ๋ฅผ ์‹œ๋„ํ•ด๋ณด์„ธ์š”.

const domNode = document.getElementById('root');
console.log(domNode); // ???
const root = createRoot(domNode);
root.render(<App />);

์˜ˆ๋ฅผ ๋“ค์–ด domNode๊ฐ€ null์ด๋ฉด getElementById ๊ฐ€ null์„ ๋ฐ˜ํ™˜ํ–ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ˜ธ์ถœ ์‹œ์ ์— ๋ฌธ์„œ์— ์ง€์ •๋œ ID๋ฅผ ๊ฐ€์ง„ ๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋ช‡ ๊ฐ€์ง€ ์ด์œ ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ฐพ๊ณ ์ž ํ•˜๋Š” ID๊ฐ€ HTML ํŒŒ์ผ์—์„œ ์‚ฌ์šฉํ•œ ID์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜คํƒ€๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”!
  2. ๋ฒˆ๋“ค์˜ <script> ํƒœ๊ทธ๋Š” HTML์—์„œ ๊ทธ๋ณด๋‹ค ๋’ค์— ์žˆ๋Š” DOM ๋…ธ๋“œ๋ฅผ โ€œ์ธ์‹ํ• โ€ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋˜๋‹ค๋ฅธ ์ผ๋ฐ˜์ ์ธ ์‚ฌ๋ก€๋Š” createRoot(domNode) ๋Œ€์‹  createRoot(<App />)์œผ๋กœ ์ž‘์„ฑํ–ˆ์„ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.


โ€œํ•จ์ˆ˜๊ฐ€ React ์ž์‹์œผ๋กœ ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹คโ€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ค๋ฅ˜๋Š” root.render์— ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด React ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹˜์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ค๋ฅ˜๋Š” <Component /> ๋Œ€์‹  Component๋กœ root.render๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

// ๐Ÿšฉ Wrong: App is a function, not a Component.
root.render(App);

// โœ… Correct: <App /> is a component.
root.render(<App />);

๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒฐ๊ณผ ๋Œ€์‹  root.render์— ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ์ „๋‹ฌํ–ˆ์„ ๋•Œ๋„ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๐Ÿšฉ Wrong: createApp is a function, not a component.
root.render(createApp);

// โœ… Correct: call createApp to return a component.
root.render(createApp());

์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋œ HTML์ด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค

์•ฑ์ด ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง ๋˜๊ณ  React์˜ ์ดˆ๊ธฐ HTML์„ ํฌํ•จํ•˜๋Š” ๊ฒฝ์šฐ์—, ๋ฃจํŠธ๋ฅผ ์ƒ์„ฑํ•ด์„œ root.render๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ๋ชจ๋“  HTML์ด ์‚ญ์ œ๋˜๊ณ  ๋ชจ๋“  DOM ๋…ธ๋“œ๊ฐ€ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์†๋„๊ฐ€ ๋Š๋ ค์ง€๊ณ , ํฌ์ปค์Šค์™€ ์Šคํฌ๋กค ์œ„์น˜๊ฐ€ ์žฌ์„ค์ •๋˜๋ฉฐ, ๊ทธ ๋ฐ–์˜ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž ์ž…๋ ฅ๋“ค์ด ์†์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋œ ์•ฑ์€ createRoot ๋Œ€์‹  hydrateRoot๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(
document.getElementById('root'),
<App />
);

API๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”. ํŠนํžˆ, ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” root.render๋ฅผ ์•„์˜ˆ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.