지난 포스트에서는 Critical Rendering Path에 대해 알아보며 브라우저의 렌더링 원리를 정리해보았습니다.
하지만 우리는 주로 React와 같은 Single Page Application을 위한 UI 라이브러리를 사용하여 웹 페이지를 개발합니다.
브라우저 렌더링 원리에 이어 리액트의 렌더링이란 무엇인지 알아보면서
SPA의 렌더링 방식에 대해 깊게 이해해봅시다.
React의 역할
우선 리액트가 어떤 역할을 하는지에 대해 알아볼까요? 리액트의 역할은 다음과 같습니다.
1. DOM 업데이트 요청 발생
2. 동시에 발생한 업데이트들을 모음
3. 모아서 한번에 수정
4. DOM에 반영
즉, 리액트란 내부적으로 동시에 발생한 업데이트를 모아 최소한의 횟수로 돔을 수정할 수 있도록 자동화시킨 도구라고 볼 수 있습니다.
리액트의 역할을 알아보았다면 리액트의 렌더링 프로세스를 알아보기에 앞서, 리액트가 사용하는 JSX 문법과 이것이 React Element로 변환된다는 사실을 알아두어야 합니다.
* React 기본 요소: JSX 와 React Element
JSX
JSX(JavaScript XML)는 React에서 컴포넌트의 구조와 요소를 쉽게 작성하고 이해할 수 있도록 도와주는 문법으로, 마크업 언어와 비슷한 형태를 가지지만, Babel과 같은 트랜스파일러에 의해 React.createElement 함수 호출 코드로 변환됩니다.
React Element
JSX의 기본 구성 요소이며, 동시에 UI 정보를 담은 javascript 순수 객체
React.createElement 함수 호출을 통해 반환되는 값.
const element = <h1>Hello, world</h1>; // JSX로 작성된 React Element
=====================================
const element = React.createElement( // 순수 자바스크립트 객체로 변환된다.
'h1',
null,
'Hello, world'
);
리액트 엘리먼트는 추후 렌더링 프로세스에서 가상 돔을 생성할 때 그 부분 요소가 됩니다.
이 가상 돔은 리액트엘리먼트와 같이 순수 객체 형태로 관리되는 특징이 있는데요,
리액트의 렌더링 프로세스를 알아보며 자세히 알아보겠습니다.
React의 렌더링 프로세스
리액트의 렌더링 프로세스는 크게 Render Phase와 Commit Phase로 구분됩니다.
1.Render Phase:
- 렌더링 프로세스가 시작되면 루트 컴포넌트에서부터 아래로 내려가며 차례로 컴포넌트를 호출하여 결과값(React Element)를 계산합니다.
- 이를 수집하여 새로운 Virtual DOM을 구성합니다. ( 이때, 가상 DOM은 실제 DOM을 복사한 순수 자바스크립트 객체 형태 로 구성되어 있으며 메모리상 관리되므로 빠르게 업데이트가 가능함. )
2.Commit Phase:
- Virtual DOM을 실제 DOM에 반영하여 갱신
- 브라우저 렌더링 패스가 다시 실행되어 변경된 UI를 표시
즉 , 리액트 컴포넌트를 호출하면 해당 컴포넌트가 표현하려는 UI 정보를 가진 순수객체가 반환됨, 그리고 이 객체들이 모아 버츄얼돔을 구성하게 되고, 이를 실제 DOM에 커밋하여 UI를 업데이트 하게 됨.
이러한 리액트의 렌더링 프로세스의 렌더단계, 커밋단계 사이에는 리액트가 화면을 업데이트하기 위한
핵심 알고리즘인 재조정 과정이 포함되어 있습니다.
재조정이 정확히 무엇일까요?
재조정(reconciliation)
재조정이란, 리액트 렌더링 프로세스의 Render phase와 Commit phase 사이에 일어나는 과정으로
이전 가상돔과 새로운 가상돔을 비교하여 변경점을 계산, 돔 업데이트 명령을 생성하는 역할을 합니다.
리액트는 React 16 버전 업데이트를 기점으로 기존의 동기적으로 처리되던 스택 재조정 알고리즘의 문제점을 극복하기 위해
새롭게 Fiber 아키텍처를 도입했습니다.
재조정 알고리즘의 구현체 : Fiber
Fiber는 리액트 재조정을 비동기로 실행시키기 위한 구현체로, fiber reconciler가 관리합니다.
따라서 Fiber 아키텍처는 아래와 같이 기존의 동기적 처리의 단점을 극복할 수 있습니다.
- 작업을 작은 단위로 분할하고 쪼갠 다음, 우선순위를 매긴다.
- 이러한 작업을 일시 중지, 나중에 다시 시작할 수 있다.
- 이전에 했던 작업을 다시 재사용하거나 필요치 않은 경우에는 폐기
위 방식의 도입으로 리액트는 재조정을 더욱 효율적으로 진행할 수 있게 된 것이죠.
리액트의 렌더링 프로세스에 대해 알아보았습니다, 그렇다면 이 렌더링이 다시 수행되는 리렌더링이란 무엇일까요?
그리고 이는 언제, 어느 상황에서 발생할까요?
리액트의 (리)렌더링은 언제 발생할까?
- useState의 setter함수 호출시, useReducer의 dispatch 호출시, 컴포넌트 key props의 변경시
- props가 변경될 때 (이를 전달받는 모든 자식컴포넌트를 리렌더링)
- 부모 컴포넌트 리렌더링 시( 자식 컴포넌트 리렌더링 )
요약하면, 리액트의 리렌더링은 props나 state가 변경될 때 트리거되는 동작으로, 렌더링 프로세스를 재수행하여 변경 사항을 반영하는 것을 말합니다.
지금까지 리액트의 렌더링 과정에 대해 알아보았습니다.
다음 포스트에서는 SPA의 동작 방식과 Server Side Rendering을 비교해보는 시간을 가져보겠습니다.
Reference
- 모던 리액트 Deep dive
- https://www.youtube.com/watch?v=N7qlk_GQRJU&t=1212s
- https://nikshindeblogs.medium.com/react-reconciliation-547024dda9fc
- https://andela.com/blog-posts/understanding-and-optimizing-react-render
- https://namansaxena-official.medium.com/react-virtual-dom-reconciliation-and-fiber-reconciler-cd33ceb0478e