MDN에서는 “DOM은 HTML, XML document와 상호작용하고 표현하는 API이다. DOM은 browser에서 로드되며, Node(이하 노드) 트리(각 노드는 document의 부분을 나타낸다)로 표현하는 document 모델이다.
위의 설명으로, Document는 HTML, XML을, Object는 노드 트리라 유추해볼 수 있다. 그렇다면 노드 트리는 무엇일까? 아래의 그림을 보면 조금 더 쉽게 이해가 갈 것이다.
현재 대부분의 웹 사이트는 수 십개 심지어 수 백, 수 천개의 페이지로 이루어졌다. 겨우 오타 하나를 잡고 싶을 뿐인데, 전체 사이트를 다시 처음부터 렌더링을 해야 하며, 해당 오타를 찾기 까지 너무나 많은 시간이 들어가 상당히 비효율적이다.
때문에, Virtual Dom
이 나왔다.
Virtual Dom(이하 가상 DOM)은 수정사항이 여러 가지 있더라도, 가상 DOM은 한 번만 렌더링을 일으킨다.
특정 컴포넌트에서 setState 호출 등의 이유로 컴포넌트 상태가 변하면 해당 컴포넌트의 shouldComponentUpdate 함수를 실행한다. 그리고 이 함수가 true를 반환하면 render 함수를 실행한다.
상태가 변한 컴포넌트를 루트 노드로 해서 깊이 우선 탐색 방식으로 각 자식 컴포넌트의 shouldComponentUpdate 함수와 render 함수를 실행한다.
이렇게 render 함수를 실행하여 얻은 새로운 Virtual DOM을 실제 DOM과 동기화되어 있는 기존 Virtual DOM과 비교해서 변경 사항을 파악한다(reconcilation). 그리고 실제로 변경된 부분만 DOM API를 호출하여 DOM에 반영하면, 브라우저가 변경 사항이 반영된 DOM과 CSSOM으로 새로운 Render Tree를 생성해서 화면을 다시 그린다.
하지만 매 렌더링이 이뤄질 때마다 매번 props가 변하는 컴포넌트는 순수 컴포넌트로 지정해도 별 의미가 없다. 오히려 shouldComponentUpdate
의 얕은 복사 로직이 불필요하게 실행되기 때문에 렌더링 시간이 늘어날 수 있다. 따라서 아래와 같이 적절한 상황에서 사용하는 것이 좋다.
매 렌더링 시 props가 매번 변경되는 컴포넌트 -> (일반) 컴포넌트
매 렌더링 시 props가 거의 변하지 않는 컴포넌트 -> 순수 컴포넌트
그리고 특정 컴포넌트의 useState
의 setState
가 호출되어 컴포넌트 상태가 변하거나 구독 중인 context의 value prop이 변경되면, shouldComponentUpdate 함수 실행 없이 무조건 렌더링이 이뤄진다.
참고 | https://velog.io/@gwak2837/React-Virtual-DOM-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0