First written: 22-12-12
Uploaded: 22-12-28
Last modified: 23-03-01
리액트에는 컴포넌트Component라는 친구가 있다.
컴포넌트Component : 앱 내 특정 파트의 html이 어떻게 보일지 정해주는 선언체
이 component가 rendering되는 방식은 다른 프레임워크와는 좀 다르다. 그런데, 그 과정을 이해하기 전에, rendering 된다는 것은 무슨 의미일까? "render"라는 동사 하나가 이루어지기 위해 그 아래에서는 어떤 일들이 일어나고 있을까?
우선 브라우저는 화면을 구성하는 일련의 코드를 받았을 때, 우선 그것을 자신이 이해할 수 있는 구조로 해석(Parsing)하는 과정을 거친다. 이것을 parsing이라 한다. HTML 파일을 parsing하여 DOM을 생성한다. CSS 파일을 parsing하여 CSSOM을 생성한다. 이 둘은 전부 Tree 구조로 이루어져 있다. DOM과 CSSOM의 차이를 조금 더 명확하게 보여줄 예시가 아래 있다.
<div>
<p style="color: black;">Hello, World</p>
</div>
아래와 같은 코드가 있다고 가정해보자. <div>
와 <p>
는 DOM과 CSSOM 모두에 존재하며, 트리 구조를 이루는 중요한 노드들이다. 반면 'Hello, World'라는 문자열은 DOM 트리에만 존재한다. <p>
노드와 연관되어 있을 것이다. 반면 color: black;
이라는 style은 CSSOM에만 존재하며 역시나 <p>
노드와 연관되어 있을 것이다.
이 두 Tree가 합쳐져 Render Tree(Frame Tree, 부르는 방식은 rendering engine에 따라 다르다)가 된다. 합치기만 하는 것은 아니다. 보여지지 않는 요소들(<head>
와 같은 요소들, 혹은 display: none;
이 적용된 요소들)은 render tree에서 제외된다. 잘못 작성된 HTML이나 CSS가 화면에 정상적으로 보이게 하는 과정도 여기서 이루어진다. 시각적으로 복잡한 요소들도 여기서 더 세분화되어 표기된다.
그 다음 단계는 Layout 단계라고도 불리는데, 정확한 배치와 style 계산을 여기서 한다. 그 이후에 브라우저는 renderer의 paint 메서드를 활용해 사용자 화면에 그려낸다. 이 일련의 과정을 보여주는 그림이 아래 있다. Paint 단계와 Composite 단계를 구분하고 세세하게 설명하는 등의 일을 여기서 할 수 있겠지만, 현재 글의 범위를 벗어난다 판단되므로 여기까지만 작성하자.
webkit 동작 방식 (그림 출처: https://d2.naver.com/helloworld/59361)
간단하게만 살펴보아도 복잡해보이는 이 과정이 가지고 있던 문제점은 약간의 변화만 있더라도 DOM 전체에 방금 말한 모든 과정이 수행되어야 했다는 점이다. 이것을 실제로 본 적이 없는 것 같다면, 지금이라도 시계 어플을 하나 만들어본 뒤 개발자 도구에서 DOM의 변화를 살펴보라. <body>
안의 <div id="container">
부터 시작해서 모든 요소들이 새로 rendering 된다는 것을 알 수 있을 것이다. 해당 코드를 만들 때 대부분의 사람이 아래와 같은 javascript 코드를 활용할 것이다.
const clock = document.querySelector('p#clock');
const getTime = () => {
// some code to get exact time
clock.innerText = `${ hour < 10 ? `0${hour}` : hour }:${ minutes < 10 ? `0${minutes}` : minutes }:${ seconds < 10 ? `0${seconds}` : seconds }`;
}
const init = () => {
setInterval(getTime, 1000);
}
init();
이 코드가 실행되면 매 초마다 브라우저는 해당 ID를 가진 노드를 찾고, 이 요소의 자식 요소를 제거하며, 새로 정의된 innerText의 내용을 가지고 요소를 업데이트한 뒤 부모 및 자식 노드의 CSS 값을 계산하고 이것이 브라우저에 paint되는 것이다. 우리가 만일 20개의 노드를 수정하고 있다면, 이 일이 각각의 노드에서 20번 일어난다. SPA(Single Page Application)를 만들었다고 생각하면, 이 상황은 더 끔찍한 것이 될 수 있다.
이를 해결하고자 나온 것이 Virtual DOM이다. React에서 많이 언급되어 React에만 있다고 생각하는 사람들도 있지만, 이건 원래 존재하던 기술이며 React뿐만 아니라 Vue.js, Elm 등에서도 사용되고 있다. Virtual DOM은 메모리에만 올라가는 DOM 혹은 offline 상태인 DOM이라고 생각하면 된다.
virtual dom (그림 출처: https://ryublock.tistory.com/41)
Virtual DOM을 활용하게 되면, 실제 DOM에 가기 전에 미리 virtual DOM에 업데이트된 DOM을 구성해본다. 이전 DOM과 새로 생긴 virtual DOM을 비교하여 바뀐 부분에 대한 내용만 실제 DOM에 전달하게 된다. 이 과정은 Reconciliation이라고 불리운다(여기서 diff 알고리즘이 사용되지만, 역시 글의 범위를 넘어서므로 패스). 이것이 DOM과 크게 다른 이유는 특히나 30개의 노드를 바꾸더라도 미리 DOM의 변경사항을 한꺼번에 파악하기 때문에 위에서 서술된 귀찮고 수많은 과정들이 단 한 번만 이루이게 된다는 점 때문이다.
당연히 요소가 많고, 그 요소들 내의 변화가 잦은 경우에는 좋은 방법일 것이다. 하지만, 잘 생각해보면 아무리 요소가 많아도 변화가 거의 없는 정적인 페이지라면 굳이 virtual DOM을 사용할 이유는 없다. 오히려 virtual DOM을 구성하는 데에 시간을 뺏길 수도 있으니까 말이다.
대부분의 웹 프레임워크는 MVC 패턴(혹은 그와 유사한 패턴)으로 이루어져 있지만, React가 신경쓰는 것은 오직 V이다.
또한 애초에 프레임워크가 아니라 라이브러리라서 새로운 기능들이 필요해지면 추가적으로 라이브러리 설치가 필요하다. 물론 자주 쓰이는 기능에 관한 라이브러리들은 유명한 것들이 이미 존재한다.
그리고 다른 웹 프레임워크나 라이브러리와 같이 사용될 수도 있다고 한다. 대표적으로 Backbone.js, Angular가 있다고 한다.
마지막으로, 이건 필자가 React를 배우게 된 이유이기도 한데, React는 거의 비슷한 문법으로 React Native를 사용할 수 있기에 웹뿐만 아니라 휴대폰 앱을 만드는 데에도 써먹을 수 있다.
참고 서적 :
김민준, 2019, 길벗, 『리액트를 다루는 기술, 개정판』
참고 사이트 :
Rendering
브라우저는 어떻게 동작하는가?
React 렌더링과 성능 알아보기
Virtual DOM
The one thing that no one properly explains about React — Why Virtual DOM
DOM과 Virtual DOM
Difference between Virtual DOM and Real DOM