ReactDOM.createRoot ๐Ÿ†š ReactDOM.render

11252 ๋‹จ์–ด reactwebdevjavascriptprogramming
ReactDOM.createRoot๋Š” ๋ฌด์—‡์ด๋ฉฐ ReactDOM.render์™€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฆ…๋‹ˆ๊นŒ?

React 18์€ ์ƒˆ๋กœ์šด ๋ฃจํŠธ API๋ฅผ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘‰ ํ˜„์žฌ API

๋ช…์‹œ์ ์œผ๋กœ ๋ Œ๋”๋งํ•  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๋ฅผ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด container๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

const container = document.querySelector('#root');

// Initial render. Container is explicitly accessed.
ReactDOM.render(<App text="Hello" />, container);

// Subsequent renders. Container is explicitly accessed.
ReactDOM.render(<App text="Hello world!" />, container);


๐Ÿ‘‰ ReactDOM.render๋Š” ๋ฌด์—‡์„ ๊ฐ€์ ธ๊ฐ€๋‚˜์š”?
render ํ•จ์ˆ˜๋Š” ์„ธ ๊ฐœ์˜ ์ธ์ˆ˜๋ฅผ ์ทจํ•ฉ๋‹ˆ๋‹ค.
  • ๋ Œ๋”๋งํ•  React ์š”์†Œ
  • ๋ Œ๋”๋งํ•  DOM ์š”์†Œ
  • ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ ํ›„ ์‹คํ–‰๋  ํ•จ์ˆ˜

  • ๊ทธ๋ฆฌ๊ณ  ๋™์ผํ•œ container ์„ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ ๋ Œ๋”๋ง๋œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

    /**
    * @param element - React element to be rendered
    * @param container - DOM element to render in
    * @param callback - function to be executed after render happens
    * @return container - container with renderned component
    */
    function render(element, container, callback) {
      // ...
    }
    


    ๐Ÿ‘‰ ReactDOM.render๋Š” ํ›„๋“œ ์•„๋ž˜์—์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?
    ReactDOM.render๋Š” ๋ช‡ ๊ฐ€์ง€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ ํ•ฉํ•œ ๋…ธ๋“œ์ธ์ง€ ์—ฌ๋ถ€
  • ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ด์ „์— createRoot๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š์•˜๋Š”์ง€ ์—ฌ๋ถ€

  • ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ˆ˜์‹ ๋œ ๋ชจ๋“  ์ธ์ˆ˜๋ฅผ legacyRenderSubtreeIntoContainer ์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

    // simplified structure
    function render(element, container, callback) {
      if (isValidContainer(element)) {
        throw Error('Target container is not a DOM element.');
      }
    
      if (isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined) {
        // don't throw an error, but logs it into console
        error('container was previously passed to ReactDOM.createRoot().');
      }
    
      return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
    }
    


    ๐Ÿ‘‰ ์ƒˆ๋กœ์šด API

    ๋ช…์‹œ์ ์œผ๋กœ ๋ Œ๋”๋งํ•  ๋•Œ๋งˆ๋‹ค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

    // First, we create a root
    const root = ReactDOM.createRoot(document.querySelector('#root'));
    
    // Initial render. Container is implicitly accessed.
    root.render(<App name="Hello" />);
    
    // Subsequent renders. Container is implicitly accessed.
    root.render(<App name="Hello world!" />);
    


    ๐Ÿ‘‰ ReactDOM.createRoot๋Š” ๋ฌด์—‡์„ ๊ฐ€์ ธ๊ฐ€๋‚˜์š”?
    createRoot ํ•จ์ˆ˜๋Š” ํ•˜๋‚˜์˜ ํ•„์ˆ˜ ์ธ์ˆ˜(๋ Œ๋”๋งํ•  DOM ์š”์†Œ)๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    ๊ทธ๋ฆฌ๊ณ  render ๋ฐ unmount ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๋Š” RootType ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    ์ถ”์‹  ๋˜ํ•œ createRoot๋Š” ๋‘ ๋ฒˆ์งธ RootOptions ์ธ์ˆ˜๋ฅผ ์ทจํ•˜์ง€๋งŒ ํ–ฅํ›„ ์ด๋ฅผ ๊ฒ€ํ† ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

    /**
    * @param container - DOM element to render in
    * @param options - options, related to hydration
    * @return RootType - instance of root
    */
    function createRoot(container, options) {
      // ...
    }
    


    ๐Ÿ‘‰ ReactDOM.createRoot๋Š” ํ›„๋“œ ์•„๋ž˜์—์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

    ๋ Œ๋”๋ง ๊ธฐ๋Šฅ ์œ„์— createRoot :
  • ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋ณธ๋ฌธ ์š”์†Œ๊ฐ€ ์•„๋‹Œ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์ข€ ๋” ์ž์„ธํ•œ ๊ฒฝ๊ณ ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค
  • .

    ๊ทธ๋Ÿฐ ๋‹ค์Œ createRoot ์ƒˆ ReactDOMRoot ๊ฐœ์ฒด๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์•„๋‹ˆlegacyRenderSubtreeIntoContainer ์ „ํ˜€!

    // simplified structure
    function createRoot(container, options) {
      if (isValidContainer(element)) {
        throw Error('Target container is not a DOM element.');
      }
    
      if (container.nodeType === 1 && container.tagName.toUpperCase() === 'BODY') {
        console.error('Creating roots directly with document.body is discouraged');
      }
    
      if (isContainerMarkedAsRoot(container) {
        if (container._reactRootContainer) {
          console.error('container was previously passed to ReactDOM.render().')
        } else {
          console.error('container has already been passed to createRoot() before.');
        }
      }
    
      return new ReactDOMRoot(container, options);
    }
    


    ์ด์ œ ์ด์ „ ๋ Œ๋”๋ง๊ณผ ์ƒˆcreateRoot ํ•จ์ˆ˜ ๊ฐ„์˜ ๋ฐ‘์ค„ ์ฐจ์ด๋ฅผ ์•Œ์•˜์Šต๋‹ˆ๋‹ค!
    legacyRenderSubtreeIntoContainer ์™€ new ReactDOMRoot ๋ฅผ ๋” ๋น„๊ตํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š”.

    ์ถ”์‹  ์ด์™€ ๊ฐ™์€ ๋” ๋งŽ์€ ์ฝ˜ํ…์ธ ๋ฅผ ์œ„ํ•ด!









    ๋‹‰ | ๋ฆฌ์•กํŠธ ํŒ…์ปค๋Ÿฌ โš›๏ธ









    React Fragments๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋ฉ๋‹ˆ๊นŒ? React๋Š” ๊น”๋”ํ•˜๊ณ  ๊นจ๋—ํ•œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์กด์žฌํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ์š”์†Œ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ ๊ณผ๋„ํ•œ ๋ž˜ํผ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ๊ฝค ๋ฉ‹์ง€์ง€๋งŒ ๋‚ด๋ถ€์—์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ? ๐Ÿงต๐Ÿ‘‡


    ์˜คํ›„ 17:34 - 2022๋…„ 1์›” 25์ผ

    ์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ