일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- JPA
- JavaSpring
- go
- typescript
- springboot
- golang
- react-hook-form
- satisfiles
- backend
- React
- css
- component
- hook
- Gin
- Redux
- RTK
- frontend
- javascript
- Spring
- ReactHooks
- java
- storybook
- Chakra
- 티스토리챌린지
- test
- tanstackquery
- 웹애플리케이션서버
- designpatterns
- 오블완
- Today
- Total
bkdragon's log
[React] Virtual DOM 본문
DOM은 웹 페이지나 웹 앱에 있는 HTML 요소들을 트리구조로 표현한 객체 모델이다. 브라우저는 DOM 을 이용해 화면에 요소들을 렌더링하는데 DOM이 가진 문제점이 몇가지 있다.
노드수가 많아질 수록 속도가 느려지고, DOM 업데이트가 잦으면 오류를 발생시킬 수 있다.
React를 활용하여 만든 웹은 SPA를 사용한다. 모든 리소스가 들어가있는 하나의 HTML 문서를 지속적으로 재렌더링 해줘야하는 문제점도 생긴다.
JavaScript에서 getElementById()
, getElementByClass()
, querySelector()
등으로 돔에 접근하는데 이때 아래와 같은 과정이 일어난다.
- 브라우저가 HTML을 분석하여 원하는 노드를 찾는다.
- 찾은 요소의 자식 요소를 제거한다.
- 요소를 업데이트한다.
- 부모 및 자식 노드에 대한 CSS를 다시 계산한다. (Reflow가 발생할 수 있다.)
- 브라우저 디스플레이에 페인팅된다. (Repaint)
수정사항이 발생할 때마다 새롭게 렌더 트리(DOM + CSSOM, 화면에 그려지는 최종 트리) 만들어지게 되는 것이다.
Virtual DOM
VDOM은 실제 DOM의 가벼운 복사이다. VDOM은 실제 DOM을 직접 처리하지 않고 메모리에서 미리 처리하고 저장한 후 실제 DOM과 동기화 한다.
아래는 과정이다.
- 데이터가 업데이트 되면 새로운 VDOM을 생성한다. (VDOM은 한 개가 아니다. React는 업데이트된 VDOM과 이전 VDOM의 두 가지 VDOM을 유지한다. )
- 이전 VDOM에 있던 내용과 현재 VDOM의 내용을 비교(Diffing 알고리즘)한 뒤 효율적으로 업데이트하기 위해 필요한 최소한의 변경 사항을 결정한다,
- 실제 DOM에 적용한다.
Diffing
React에서 두 개의 VDOM을 비교할 때 사용하는 알고리즘으로 두 가지의 가정을 통해 복잡도를 O(n)으로 줄인 알고리즘이다. (트리 비교 알고리즘은 원래 O(n^3)이다.)
1. Two elements of different types will produce different trees.
: 서로 다른 타입을 가진 두 엘리먼트는 다른 트리를 만들어 낸다.
2. The developer can hit at which child elements may be stable across different renders with a key prop.
: 개발자가 key prop를 통해 자식 엘리먼트의 변경 여부를 표시할 수 있다.
Element의 타입이 다른 경우
- Root 엘리먼트의 타입이 다르면 DOM Tree를 버리고 새로운 트리를 구축한다.
- 엘리먼트가 제거되면 해당 엘리먼트와 하위 모든 엘리먼트의 state도 사라진다.
<!-- div와 span은 다르기 때문에 div는 제거된 후 span과 그 하위 엘리먼트가 추가됨 -->
<div>
<Counter />
</div>
<span>
<Counter />
</span>
DOM의 Element의 타입이 같은 경우
- Element의 타입이 같은 경우,Attribute(속성)을 확인하여 동일한 내역은 유지하고 변경된 속성만 갱신한다.
- 해당 처리는 하위의 자식 노드들에게 재귀적으로 처리한다.
- style 갱신도 변경 사항만 갱신 합니다.
<!-- Attribute 갱신 -->
<div className="before" title="stuff" />
<div className="after" title="stuff" />
<!-- Style 갱신 // 결과적으로 color만 갱신, fontWeight는 유지 -->
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}} />
같은 타입의 Component Element
- 컴포넌트가 갱신되면 인스턴스는 동일하게 유지되어 렌더링 간 state가 유지된다.
- 새로운 내용 반영을 위해서 props를 갱신한다.
반복적인 Element 처리
- DOM 노드의 자식들을 반복적으로 처리할 때, 기본적으로 두 트리를 순차적으로 비교하고 차이점이 있으면 변경한다.
- 순회 비교를 하기 때문에 Element 리스트의 앞에 추가하는 것 보다 뒤에 추가하는 것이 성능상으로 좋다.
<!-- 문제 X -->
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
<!-- 성능상 문제 발생할 수 있음 -->
<ul>
<li>2</li>
<li>3</li>
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
Keys
- 4번에서 발생한 문제를 해결하기 위해서 key 속성을 지원한다.
- React는 key 속성을 통하여 두 트리를 비교하여 일치하는지 확인한다,
- 차이점이 발생하면 추가한다.
- 일반적으로 React에서 반복문을 통하여 Element를 생성할때 key 속성을 요구한다.
- 하지만 위의 Case 외에 반복적으로 Element를 사용하고 상태에 따라서 Element가 추가/삭제될 수 있는 경우 key 속성을 사용하는 것이 성능상으로 좋다.
- 반복되는 Element의 key 속성에 index를 사용을 권장하지 않는 이유는 반복되는 Element의 항목들이 재배열 되는 경우 비효율적으로 동작하기 때문이다.
<!-- key 속성으로 4번의 성능 문제 해결 -->
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
Reference
'React' 카테고리의 다른 글
클로저와 useState (0) | 2023.07.10 |
---|---|
[React] 성능 최적화 (0) | 2023.06.29 |
[React Query] Mutation 이후 캐시 데이터 직접 변경하기 (0) | 2023.06.24 |
[React-hook-form] register, handleSubmit 살짝 파헤치기 (0) | 2023.06.12 |
커링과 HOC (0) | 2023.05.31 |