렌더링
렌더링이란?
리액트에서 렌더링이란 화면에 특정한 요소를 그려내는 것을 의미한다.
브라우저는 DOM요소를 계산하고 그려내는 렌더링 과정을 거치고, 우리는 브라우저에서 제공하는 DOM API를 자바스크립트를 통해 호출해 화면을 변화시킨다.
하지만 Vanila JavaScript를 이용해 DOM에 직접 접근하고 최적화하는 것은 애플리케이션 규모가 커질수록 관리하기 힘들다. 때문에 핵심 UI를 선언하기만 하면 DOM을 조작해서 UI를 그려내고 변화시키는 일은 라이브러리나 프레임워크가 대신해주는 방식을 찾게 됨. React, Vue, Angular 등이 등장하게 된 이유.
리액트에서 리렌더링 되는 시점
리액트에서 state를 사용하는 이유는 UI와 상태(state)를 연동시키기 위함이다. UI와 연동 되어야 하고, 변할 여지가 있는 데이터들을 state라는 형태로 사용하는 것.
그리고 데이터가 변경되었을 때 UI를 이에 맞춰 변화시키기 위해 state 변경 방법을 제한시키고(setState), 이 함수가 호출될 때마다 리렌더링 되도록 설계되었음.
즉, 리액트에서 리렌더링 되는 시점은 state가 변했을 때.
특정 컴포넌트의 state가 변하면 해당 컴포넌트와 하위 컴포넌트 모두 리렌더링이 발생한다.
리액트의 렌더링 과정
state가 변화되고 브라우저상의 UI에 반영되기까지 각 컴포넌트는 아래의 4단계를 거치게 된다.
- 기존 컴포넌트의 UI를 재사용할 지 확인한다.
- 함수 컴포넌트: 컴포넌트 함수를 호출한다 / Class 컴포넌트: render 메소드를 호출한다.
- 2의 결과를 통해서 새로운 VirtualDOM을 생성한다.
- 이전의 VirtualDOM과 새로운 VirtualDOM을 비교해서 실제 변경된 부분만 DOM에 적용한다.
4번 과정을 왜 하는지 좀 더 자세히 알아보도록 하겠다.
브라우저는 근본적으로 화면을 보여주기 위해서 HTML, CSS, JavaScript를 다운로드 받고 그를 처리해서 화면에 픽셀 형태로 그려낸다. 이 과정을 CRP(Critical Rendering Path)라고 부른다.
Critical Rendering Path는 기본적으로 아래의 과정을 수행한다.
- HTML을 파싱해서 DOM을 만든다.
- CSS를 파싱해서 CSSOM을 만든다.
- DOM과 CSSOM을 결합해서 Render Tree를 만든다.
- Render Tree와 Viewport의 width를 통해서 각 요소들의 위치와 크기를 계산한다.(Layout)
- 지금까지 계산된 정보를 이용해 Render Tree상의 요소들을 실제 Pixel로 그려낸다. (Paint)
이후 DOM 또는 CSSOM이 수정될 때마다 위의 과정을 반복하기 때문에 이 과정을 최적화 하는 것이 중요한 포인트다.
특히 위 과정중에서 Layout, Paint 과정은 특히나 많은 계산을 필요로 하는 부분이다.
따라서 리액트는 이 CRP이 수행되는 횟수를 최적화 하기 위해서 VirtualDOM을 사용한다.
렌더링 최적화
리액트가 내부적으로 수행하는 최적화
리액트에서는 UI의 변화가 발생하면 변화에 필요한 DOM조작들을 매번 바로 실제 DOM에 적용하는 것이 아니라, VirtualDOM이란 리액트가 관리하고 있는 DOM과 유사한 객체형태로 만들어낸다. 그리고 이전의 VirtualDOM과 새로운 VirtualDOM을 비교해서 실제로 변화가 필요한 DOM요소들을 찾아낸다. 그다음에 한 번에 해당 DOM요소들을 조작한다.
즉, 렌더링 4단계에서 4.이전의 VirtualDOM과 새로운 VirtualDOM을 비교해서 실제 변경된 부분만 DOM에 적용한다.
이 처리를 통해서 브라우저에서 수행되는 CRP의 빈도를 줄일 수 있고,
이게 VIrtualDOM을 이용해서 리액트가 수행하는 최적화인 것이다.
개발자가 할 수 있는 최적화
위에 설명한 렌더링 4단계 중,
- 기존 컴포넌트의 UI를 재사용할 지 확인한다.
- 2의 결과를 통해서 새로운 VirtualDOM을 생성한다.
두 부분에 해당하는 최적화를 할 수 있다.
좀 더 자세히 말하자면 1. 기존 컴포넌트의 UI를 재사용할 지 확인한다. 의 경우에는 만약 리렌더링 될 컴포넌트의 UI가 이전의 UI와 동일하다고 판단되는 경우 새롭게 컴포넌트 함수를 호출하지 않고 이전의 결괏값을 그대로 사용하도록 함으로써 최적화를 수행할 수 있다.
3. 2의 결과를 통해서 새로운 VirtualDOM을 생성한다. 의 경우는 컴포넌트 함수가 호출되면서 만들어질 VirtualDOM의 형태를 비교적 차이가 적은 형태로 만들어지도록 한다.
예를들어 UI를 바꾸기 위해서 <div> tag를 <span> 태그로 변환시키는 것보다는 <div className="block" />을 <div className="inline">으로 변환시키는 것이 VirtualDOM끼리 비교했을 때 차이가 적은 형태로 만들어진다.