아래 포스팅에서 자세하게 다뤘습니다.
https://velog.io/@twoone14/브라우저-렌더링-과정
아래는 브라우저 렌더링의 간단한 다이어그램이다.

간단하게 설명한다면
브라우저가 렌더링을 하기 위해 html 문서를 object 모델로 파싱한 객체 이다.


<button id="plus">+</button>
<div id="counter">0</div>
<script>
const btn = document.getElementById('plus');
btn.addEventListener('click', () => {
const counter = document.getElementById('counter');
const count = parseInt(counter.innerText);
counter.innerText = count + 1;
})
</script>
위 코드는 DOM 을 조작하여 카운트 기능을 만든것이다. 이렇게 DOM의 노드를 직접 접근, 수정하여 다시 DOM을 렌더링 시킬수 있다.
DOM 을 직접 조작하여 화면을 업데이트를 하기 위해서는
렌더링 과정의 HTML, CSS 파싱, 화면에 Painting 하는 과정을 모두 재실행 한다.
위와같은 동작은 프로그램의 성능을 저하시키는데 주요 원인이 된다. 😢
CSR 을 사용하기 전 SSR에서는 렌더링이 준비가 완료된 데이터를 클라이언트가 받았기 때문에 동적으로 바뀌는 DOM 조작은 크게 문제가 되지 않았다.
하지만 CSR 가 등장하며 복잡하게 업데이트 되는 DOM들은 최적화가 필요했고
이렇게 등장한 것이 Virtual DOM 이다.
Virtual DOM(가상돔)은 실제 DOM과 같은 내용을 담고 있는 복사본이다.
복사본은 실제 DOM이 아닌 JS 객체형태로 메모리 안에 저장되어 있다!

DOM tree를 생성하고 렌더링 될때 브라우저에 렌더링 될때
Virtual DOM 은 DOM 트리를 복사하여 복사본으로 가지고 있게 된다.
만약 DOM 을 조작하는 업데이트가 생겼을때
변화가 완료된 새로운 Virtual DOM 을 만들게 된다.
변화 이전 DOM 과 변화 후 DOM 두개를 가지고 있음
변화 이전 V-DOM 과 이후 V-DOM 을 비교하여 변화된 부분만을 확인하여
실제로 변화된 부분만 실제 DOM 을 업데이트 한다.
결국 V-DOM 은 변화 내용을 캐싱하거나 버퍼링 (모아뒀다 한번에) 하는 동작으로 최적화 한다!
React에서는 V-DOM으로 변경 상태를 체크후 변경부분만 재 렌더링 하는것으로 최적화 한다.
React에서 리스트를 렌더링 하는 코드를 보자
const TODO_LIST = [
{ id: 1, value: "할일 1" },
{ id: 2, value: "할일 2" },
{ id: 3, value: "할일 3" },
];
return (
<div>
{TODO_LIST.map(({ id, value }) => (
<div>value</div>
))}
</div>
);

위 코드의 브라우저 콘솔은 아래와 같은 경고를 준다.

리액트를 해봤다면 많이 접해봤을 경고라 생각한다.
이 경고는 리액트의 재 렌더링 과정에서 key prop이 중요한 역할을 하기 때문에 나오는 경고이다.
아래와 같은 코드를 보자
return (
<ul>
<li>할일 1</li>
<li>할일 2</li>
</ul>
);
위 코드에서 할일 3이 추가 된다고 해보자 아래에 추가 되는게 자연스럽게 생각된다.
return (
<ul>
<li>할일 1</li>
<li>할일 2</li>
<li>할일 3</li>
</ul>
);
위와같은 리액트 코드에선 새롭게 생긴 할일 3만 재 렌더링 되는게 맞다 하지만 아래와 같이 위에 생긴다면 어떻게 될까?
return (
<ul>
<li>할일 3</li>
<li>할일 1</li>
<li>할일 2</li>
</ul>
);
리액트는 리스트의 모든 변경이 감지됨을 확인하고 할일 1, 2을 지웠다가 3,1,2, 순으로 렌더링 하게 된다.
이는 V-DOM을 활용해 최적화한 상태가 아니기 때문에 React의 key prop을 이용해 최적화 가능하다.
만약 아래와 같이 key prop으로 각 id 를 준다면
return (
<div>
{TODO_LIST.map(({ id, value }) => (
<div key={id}>{value}</div>
))}
</div>
);
// 새롭게 추가되는 할일 {id : 3, value : “할일 3” }
새롭게 추가되는 할일이 배열에 앞에 추가되도 V-DOM 이 감지하는 상태 변화는 key 값으로 판단하여 할일1, 2 는 재 렌더링 목록에 포함되지 않게 되는것이다.
따라서 리액트에서 리스트를 렌더링할때는 index를 key값으로 주지 않도록 한다.
배열의 값이 앞에 추가되기 라도 한다면 모든 index가 바뀌고 모든 아이템이 리 렌더링 되기 때문이다.