토막지식시리즈/React 토막지식

리액트에서 "렌더링(rendering)"이란?

GrapeMilk 2024. 8. 23. 23:07

프론트엔드에서 렌더링은 범용적인 용어이다, 브라우저에서도 리액트에서도 렌더링이 발생한다. 리액트에서 렌더링은 무엇일까?

 

TL;DR 렌더링이란?

브라우저 DOM을 직접적으로 수정하는 비용을 줄이기 위해 React에서 수행하는 작업이며 브라우저 DOM을 업데이트할 범위를 결정하고 반영하는 과정.

 

Trigger, Render, Commit

리엑트는 "렌더링과정"을 통해 브라우저 DOM을 업데이트할 범위를 결정하고 반영한다. 여기서 렌더링과정은 "Trigger", "Render", "Commit" 단계로 나뉜다. 

 

Trigger

렌더링을 유발하는 단계로 두 가지 상황이 있다.

1. 앱 시작 초기(initial render)

initial render는 target DOM node(root)와 함께 createRoot를 호출한 뒤 render 함수를 실행하는 과정이다.

 * createRoot는 인수로 전달된 요소를 리액트 앱의 루트로 만들어 반환한다. 트리 형태의 Virtual Dom에서 루트 요소가 된다.

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

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

 

렌더링 결과 (공식문서 참고)

 

2. state의 변경이 있을 때(re-render)

initial render 이후에는 set(State) 함수를 통해 state를 변경하여 리렌더링 할 수 있다.

 

Render

화면에 그릴 요소를 계산하기 위해 리엑트는 components를 호출하는데 이를 Rendering 이라고 한다.

 - initial render에서는 root component를 호출한다.

 - 리렌더시에는 state가 변경된 component를 호출한다.

 

이런 호출은 재귀적으로 반복된다. 호출된 컴포넌트가 다른 컴포넌트를 return 한다면 리액트는 다음 스텝으로 return된 컴포넌트를 렌더한다. 이 호출은 더이상 반환되는 컴포넌트가 없을 때까지 반복된다. 이런 과정을 통해 리액트는 어떤 요소를 하면에 그려야 하는지 알 수 있다.

// Gallery.js

export default function Gallery() {
  return (
    <section>
      <h1>Inspiring Sculptures</h1>
      <Image />
      <Image />
      <Image />
    </section>
  );
}

function Image() {
  return (
    <img
      src="https://i.imgur.com/ZF6s192.jpg"
      alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals"
    />
  );
}

// index.js

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

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

 

 - 리액트는 initial render에서 section, h1, 세개의 img Dom nodes를 생성한다.

 - 리렌더시에는 이전 렌더와 현재 렌더를 비교하여 변화된 부분을 계산한다. 

 

Commit 

Render 단계를 통해 호출된 컴포넌트들이 브라우저 DOM에 적용되는 단계. 

 - initial render시에는 DOM API인 appendChild() 함수를 사용하여 render를 통해 생성한 노드들을 돔에 반영한다.

 - 리렌더시에는 변화된 부분만 DOM에 반영한다.

 

리액트는 render시에 변화된 부분이 있는 경우에만 DOM을 업데이트한다. 

아래에는 부모에게 time 값을 전달받아 props가 변경되어 리렌더링이 일어나는 Clock 컴포넌트가 있다. 매초마다 변경된 time을 받기 때문에 Clock도 매초마다 리렌더링된다. 이 때 input 컴포넌트에는 변화가 없다. 리액트는 이전, 이후 렌더에서 input 컴포넌트에 변화가 없다고 판단하기 때문에 input에 어떤 값을 입력해도 리셋되지 않는다.

export default function Clock({ time }) {
  return (
    <>
      <h1>{time}</h1>
      <input />
    </>
  );
}

 

 

Browser paint

리엑트가 렌더링을 마치고 DOM을 업데이트 한 뒤, 브라우저는 화면을 repaint 한다. 즉 "브라우저 렌더링"이 시작된다.

 

ref

리액트 공식문서, https://beta.reactjs.org/learn/render-and-commit)

직접 답변한 커리어리 글 https://careerly.co.kr/qnas/1400