많은 개발자들이 리액트를 사용하는 이유 중 하나는 빠른 속도를 제공하기 때문이다. 리액트는 가상 돔(Virtual DOM)을 사용해 보다 효율적으로 원하는 페이지를 브라우저에 빠르게 그려준다. Virtual DOM에 대해 이해하기 전에 간단히 DOM에 대해 설명하도록 하겠다.
DOM이란 HTML 요소들을 tree 형태로 표현한 것을 의미한다. 하나하나의 HTML 요소들을 담고 있는 웹페이지를 Document라고 하는데, 이를 브라우저는 분석해 페이지를 띄워주게 된다.
DOM tree 안에는 각각의 요소에 상응하는 노드가 들어있다. 개발자들은 DOM이 제공하는 API를 통해 DOM 구조에 접근을 하고, 원하는 요소를 조작할 수 있게 된다. 이를 DOM 조작이라고 부르기도 한다.흔히 getElementById, querySelector과 같은 API를 통해 DOM 구조안의 요소에 접근해 원하는 내용, 스타일, 레이아웃 등을 수정한다.
웹의 복잡도가 증가하며, DOM 조작도 이에 맞춰 점점 빈번하게 일어나게 되었다. DOM 조작이 많이 발생할 경우, 상당히 비효율적이다. Virtual DOM은 이러한 상황을 해결하기 위해 나타난 개념이다.
Virtual DOM은 하나의 가상 레이어이다. Virtual DOM에 적용하는 변경사항은 DOM에 바로 반영되지 않는다. 다만 그 변경사항들을 모아두고, 한번에 DOM한테 보내게 된다. 그러면 DOM은 업데이트를 한 번만 하게 되고, 렌더도 한 번만 실행하면 되는 것이다.
리액트는 항상 위 2개의 Virtual DOM 객체를 가지고 있다. 리액트는 State가 변경될 때마다 재렌더링이 일어난다. 이 시점마다 새로운 내용이 담긴 Virtual DOM을 생성하게 된다.
Diffing은 효율적인 알고리즘을 사용하여 진행되기 때문에 어떤 요소에 차이가 있는지를 매우 신속하게 파악할 수 있게 된다. 리액트는 이를 통해 차이가 발생한 부분만을 실제 DOM에 적용하게 된다. 이 과정을 Reconciliation(재조정)이라고 한다. 이 과정이 매우 효율적인 이유는 Batch Update 때문이다. 모든 요소들을 집단화시켜 이를 한번에 실제 DOM에 적용하는 방식이다.
DOM 조작에 비용이 가장 많이 발생하는 지점은 브라우저에 화면을 그려주는 작업인 만큼 Batch Update는 변경된 요소들을 별개로 그려주는 것이 아니라, 변경된 내용을 한 번에 받아와 이를 실제 DOM에 한번에 적용시켜준다는 점이 매우 효율적이다.
리액트에서 map으로 컴포넌트를 반복 렌더링 할 경우 주의 문구를 확인할 수 있다. 리액트가 setState를 할때, 비동기로 동작하고 연속적으로 호출했을 때 배치 처리를 했는데, 그 이유는 리액트는 효율적으로 DOM을 업데이트하기 위해서였다. 리액트 입장에서는 컴포넌트를 반복해서 렌더링하는 일은 비효율적이다.
이러한 문제를 해결하기 위해 존재하는 것이 key 속성이다. 자식들이 key를 가지고 있다면, 리액트는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 캐치할 수 있고 효율적으로 렌더링 할수 있게 된다. 또한 요소들의 순서가 바뀔 때 엉뚱한 곳에 렌더링될 수 있기 때문에 key 속성을 지정해 주어야 한다.
export default function ListItem({
onClickTitle,
badges,
}) {
return (
<ListItemLayout>
<div>
<div role="button" onClick={onClickTitle} className={styles.title}>
Issue Example
{badges &&
badges.map((badgeProps, idx) => (
<Badge key={idx} {...badgeProps} />
))}
</div>
<div className={styles.description}># Description</div>
</div>
</ListItemLayout>
)
}
map 함수 인자로 전달되는 함수 내부에서 key를 컴포넌트 props를 설정하는 것과 같이 작성하면 된다. keys는 요소의 교유한 값을 사용해야 하며, 배열 요소의 고유한 값을 사용하거나 index로 사용한다. 단, 항목의 순서가 바뀔 수 있는 경우, 순서가 바뀌면 index도 바뀌기 때문에 권장하지는 않는다.