티스토리 뷰

React의 작동 흐름

 

React의 작동 흐름은 크게 네 가지 단계로 나누어진다.

  • Mount: 컴포넌트가 새롭게 생성되는 단계이다. 컴포넌트 함수가 실행되고 결과물로 나온 Element들이 가상 DOM에 삽입되고 실제 DOM을 업데이트하기까지의 과정이다.
  • Trigger: 렌더링을 유발한다. 앱 시작 초기 또는 state의 변경이 있을 때(re-render)에 해당한다.
  • Render: 브라우저 DOM에 반영될 요소를 계산하는 단계이다. 브라우저 DOM에 업데이트 하기 전에 가상돔을 조작하여 업데이트할 모양을 만들어 내는 단계이다. 가상돔을 통해 업데이트를 미리 실행하는 이유는 브라우저 DOM을 직접 조작하는 비용(repaint, reflow)가 크기 때문이다. 초기 렌더라면 루트 컴포넌트를 호출하여 전체 엘리먼트에 대한 가상돔을 만들지만, Re-render의 경우 이전 렌더와 비교하여 변화가 있는 컴포넌트를 호출한다.
  • Commit: Render 단계를 통해 호출된 컴포넌트들이 브라우저 DOM에 적영되는 단계이다. Render 단계에서 변화가 있던 부분만 DOM에 마운트되고 라이프 사이클을 실행한다.

이렇게 React의 작동 흐름은 사용자와 상호작용하며 동적으로 UI를 업데이트 한다.

 

이를 조금 더 예를 들어 설명해보자. (참고)

컴포넌트는 화면에 표시되기 전에 React로 렌더링이 먼저 되어야 한다.

컴포넌트가 요리사로 비유하고 React는 고객(사용자)의 요청을 접수하고 주문을 전달하는 웨이터로 비유한다.

 

UI를 요청하고 제공하는 프로세스는 크게 세 단계로 구성된다.

 

Illustrated by Rachel Lee Nabors

1단계, 렌더링 트리거 (Triggering a render) : 손님의 주문을 받고 주방으로 전달

컴포넌트가 렌더링이 되는 이유는 두 가지가 있다.

  • 초기 렌더링

앱이 시작되면 초기 렌더링을 트리거 해야 한다.

createRoot 대상 DOM 노드를 호출한 뒤 render 메서드를 사용하여 해당 컴포넌트를 렌더링 한다.

// Greeting.jsx
const Greeting = () => {
	return <h1>환영합니다!</h1>
}

export default Greeting;

 

// main.jsx
import Greeting from './Greeting.jsx';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

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

root.render(
	<StrictMode>
		<Greeting />
	</StrictMode>
);

 

 

  • 컴포넌트 또는 상위 항목의 state가 업데이트 되어 다시 렌더링(리렌더)를 하는 경우

 

Illustrated by Rachel Lee Nabors

 

컴포넌트가 처음 렌더링 되면 set 함수를 통해 state를 업데이트하여 추가 렌더링을 트리거 할 수 있다.

컴포넌트의 state를 업데이트하면 렌더링이 자동으로 큐(queue)에 추가된다.

2단계, 컴포넌트 렌더링 (Rendering the component) : 주방에서 주문한 음식을 준비

React가 구성 요소를 렌더링하는 단계이다.

React는 렌더링을 트리거 한 후 컴포넌트를 호출하여 화면에 표시할 내용을 파악한다.

ㄴ “렌더링”은 React가 컴포넌트를 호출하는 것이다.

// Greeting.jsx
const Greeting = () => {
  return (
    <section>
      <h1>환영합니다!</h1>
      <DuckImage />
      <DuckImage />
      <DuckImage />
    </section>
  );
};

const DuckImage = () => {
  return (
    <img
      src="https://www.shutterstock.com/image-vector/cute-cartoon-rubber-duck-vector-600nw-2276837591.jpg"
      alt="DuckImage"
      width="50px"
      height="50px"
      style={{
        margin: 8,
      }}
    />
  );
};

export default Greeting;

  • 초기 렌더링 시 React는 루트 컴포넌트를 호출한다.

React는 <section> <h1> <img> 세 개의 태그에 대한 DOM 노드를 생성한다.

 

  • 이후의 렌더링에서 React는 렌더를 트리거한 상태 업데이트의 함수 컴포넌트를 호출한다.

다시 렌더링을 하는 동안 React는 이전 렌더링 이후 변경된 속성이 있는지 계산한다.

다음 단계인 커밋까지 해당 정보로 아무 작업도 수행하지 않는다.

 

해당 프로세스는 재귀적이다.

업데이트된 컴포넌트가 다른 컴포넌트를 반환하면 React는 그 다음에 해당 컴포넌트를 렌더링하고 만약 그 컴포넌트도 무언가를 반환하면 그 다음에 렌더링하는 식이다.

 

이 프로세스는 중첩된(nesting) 컴포넌트가 없을 때까지 반복되고 React는 화면에 정확히 어떤 내용을 표시해야 하는지 파악하게 된다.

3단계, DOM에 커밋 (Committing to the DOM) : 테이블 위에 주문한 음식을 배치

React는 DOM에 변경 사항을 커밋한다.

즉, 컴포넌트를 렌더링(호출)한 후 React는 DOM을 수정한다.

  • 초기 렌더링의 경우

React는 appendChild() DOM API를 사용하여 생성된 모든 DOM 노드를 화면에 배치한다.

ㄴ appenChild() 메서드는 노드를 특정 부모 노드의 자식 노드 리스트 중 마지막 자식으로 붙이는 메서드이다.

 

  • 재렌더링(re-renders)의 경우

다시 렌더링할 때 React는 DOM이 최신 렌더링 출력과 일치하도록 최소한의 필수 작업을 적용한다.

ㄴ 이 작업은 렌더링 중에 계산된다.

 

React는 렌더링 간에 차이가 있는 경우에만 DOM 노드를 변경한다.

브라우저 렌더링

렌더링이 완료되고 React가 DOM을 업데이트 한 후 브라우저는 화면을 다시 칠한다.

이 프로세스를 “브라우저 렌더링”이라고 한다.

Illustrated by Rachel Lee Nabors