컴포넌트가 화면에 보이기 전에는 반드리 리액트로 렌더링이 되어야해요. 이 과정을 단계별로 이해하면 코드가 실행되는 방법을 알고 동작을 설명하는데 도움이 될 거예요.
이 페이지에서는
- 리액트에서 렌더링이란 무엇인지
- 리액트는 컴포넌트를 언제 그리고 왜 렌더링하는지
- 화면에서 컴포넌트를 보여주려면 어떤 단계를 거치는지
- 렌더링이 왜 항상 DOM 업데이트를 발생시키지는 않는지
를 알아볼 거예요.
컴포넌트를 재료를 조합하여 맛있는 요리를 만드는 부엌의 요리사라고 생각해보세요. 이 시나리오에서 리액트는 손님의 주문을 받고 음식을 가져다주는 웨이터예요. UI를 요청하고 제공하는 이 과정은 세 단계를 거쳐요.
- 렌더링 발생시키기 (손님의 주문을 부엌에 알려주기)
- 컴포넌트 렌더링하기 (부엌에서 주문 준비하기)
- DOM에 커밋하기 (손님에게 음식 서빙하기)





Illustrated by Rachel Lee Nabors (출처: react.dev)
Step 1: Trigger a render | 1단계 : 렌더링 발생시키기
컴포넌트가 렌더링되는 이유에는 두 가지가 있어요.
- 컴포넌트의 최초 렌더링이기 때문에
- 컴포넌트의 상태가 업데이트 되었기 때문에
Initial render | 최초 렌더링
앱을 시작하면 최초 렌더링을 발생시켜야해요. 프레임워크와 샌드박스는 때때로 이 코드를 숨기지만 해당하는 DOM 노드로 createRoot
를 호출하고 해당 컴포넌트로 render
메서드를 호출하여 이 작업을 완료해요.
root.render()
를 주석처리해서 컴포넌트가 사라지는 걸 확인하세요!
Re-renders when state updates | 상태가 업데이트될 때의 리렌더링
컴포넌트가 처음으로 렌더링되면 상태를 set
함수로 업데이트하면 그 이후의 렌더링을 발생시킬 수 있어요. 컴포넌트의 상태를 업데이트하면 자동적으로 렌더링이 대기열로 들어가요. (이 과정은 식당에서 손님이 첫 번째 주문을 넣은 후에 허기나 갈증에 대한 상태에 따라 손님이 차, 디저트 그리고 다양한 것들을 주문한다고 생각해보세요.)





Illustrated by Rachel Lee Nabors (출처: react.dev)
Step 2: React renders your components | 2단계: 리액트는 컴포넌트를 렌더링해요.
렌더링이 발생되면, 리액트는 어떤 컴포넌트를 화면에 보여줄지를 찾기 위해 컴포넌트를 호출해요. "렌더링"은 리액트가 컴포넌트를 호출하는 것이에요.
- 최초 렌더링에서 리액트는 루트 컴포넌트를 호출해요.
- 이후의 렌더링에서 리액트는 상태를 업데이트해서 렌더링을 발생시킨 함수 컴포넌트를 호출해요.
이 과정은 재귀적이에요. 만약 업데이트된 컴포넌트가 다른 컴포넌트를 반환한다면 리액트는 그 컴포넌트를 그 다음에 렌더링하고 만약 그 컴포넌트도 무언가를 반환한다면, 리액트는 그 컴포넌트도 렌더링하는 방식으로 렌더링을 진행해요. 이 과정은 중첩된 컴포넌트가 더 없을 때까지 반복되고 리액트는 정확히 어떤 화면을 보여줘야하는지를 알고 있어요.
아래의 예시에서 리액트는 Gallery()
와 Image()
를 여러 번 호출해요.
- 최초 렌더링 동안 리액트는
<section>
,<h1>
과 3개의<img>
태그의 DOM 노드를 만들어요. - 리렌더링동안 리액트는 이전 렌더링에서 달라진 속성이 있다면 재연산해요. 다음 단계인 커밋 단계까지는 해당 정보로 아무것도 하지 않아요.
함정
리렌더링은 순수 함수여야만해요.
- 동일한 입력엔 동일한 출력을. 같은 입력값을 넣었을 때 순수함수는 항상 같은 JSX를 반환해야해요. (토마토 샐러드를 누군가 주문했다면, 양파 샐러드를 받지 않아요!)
- 자신의 일만 처리해요. 렌더링 전에는 기존 객체나 변수를 바꾸지 않아요. (누군가의 주문은 다른 누군가의 주문을 바꾸지 않아요!)
그렇지 않다면 코드베이스의 복잡도가 커질수록 혼란스러운 버그와 예측하지 못한 동작을 마주할 거예요. "엄격한 모드"에서 개발한다면 리액트는 각 컴포넌트의 함수를 두번씩 호출하고 이는 함수가 순수하지 않아서 발생하는 표면적 실수들을 드러내는데 도움을 줘요.
성능 최적화
Step 3: React commits changes to the DOM | 3단계: 리액트는 DOM의 변경 사항을 커밋해요.
컴포넌트를 렌더링(호출)한 이후에, 리액트는 DOM을 수정해요.
- 최초 렌더링에서 리액트는 DOM API인
appendChild()
를 사용하여 스크린에 생성된 모든 DOM 노드를 넣어요. - 리렌더링에서 리액트는 최근 렌더링 결과와 일치하는 DOM을 만들기 위해 (리렌더링동안 계산된) 필요한 최소한의 연산을 적용해요.
리액트는 렌더링 간의 차이가 있는 DOM 노드만을 변경해요. 예를 들어 아래의 컴포넌트는 매 초마다 부모 컴포넌트에서 다른 prop을 전달받아 리렌더링돼요. 컴포넌트가 리렌더링될 때 <input>
에 텍스트를 넣고 value
를 업데이트하지만 어떻게 텍스트는 사라지지 않는지에 주목하세요.
그 이유는, 마지막 단계에서 리액트는 <h1>
의 콘텐츠만 새로운 time
으로 업데이트하기 때문이에요. <input>
은 JSX에서 이전과 같은 위치에 있는 것처럼 보이기 때문에 리액트는 <input>
이나 그 value
는 건들지 않아요!
Epilogue: Browser paint | 에필로그: 브라우저 페인트하기
렌더링이 끝나고 리액트가 DOM을 업데이트하면, 브라우저는 화면을 리페인팅해요. 이 과정은 "브라우저 렌더링"으로 알려져 있지만 문서 전체적으로 생길 혼란을 피하기 위해 "페인팅"이라고 할게요.
Illustrated by Rachel Lee Nabors (출처: react.dev)
Recap | 요약
- 리액트에서 스크린은 아래 세 단계를 통해 업데이트 돼요.
- 렌더링 발생시키기
- 렌더링하기
- 커밋하기
- 컴포넌트 내에 있는 실수를 찾으려면 엄격한 모드를 사용하세요.
- 만약 마지막 렌더링과 렌더링 결과가 동일하다면 리액트는 DOM을 건들지 않아요.