Virtual DOM과 React의 Key props

이원찬·2024년 7월 13일

React

목록 보기
14/17

브라우저 렌더링 과정 알아보기 🎨

아래 포스팅에서 자세하게 다뤘습니다.

https://velog.io/@twoone14/브라우저-렌더링-과정

아래는 브라우저 렌더링의 간단한 다이어그램이다.

간단하게 설명한다면

  1. DOM Tree를 생성하고
  2. RenderTree를 만들고
  3. Layout 단계 ( Reflow )를 거치고 ( 기하학적 위치(스크린 좌표) 를 정한다. )
  4. Painting 과정 ( 모든 요소의 색을 입히는 과정 )

DOM이란? 🤔

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

DOM을 조작하자

<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 조작의 비효율성 ⚠️

DOM 을 직접 조작하여 화면을 업데이트를 하기 위해서는

렌더링 과정의 HTML, CSS 파싱, 화면에 Painting 하는 과정을 모두 재실행 한다.

위와같은 동작은 프로그램의 성능을 저하시키는데 주요 원인이 된다. 😢

CSR 의 등장과 함께 제기된 문제 ❗

CSR 을 사용하기 전 SSR에서는 렌더링이 준비가 완료된 데이터를 클라이언트가 받았기 때문에 동적으로 바뀌는 DOM 조작은 크게 문제가 되지 않았다.

하지만 CSR 가 등장하며 복잡하게 업데이트 되는 DOM들은 최적화가 필요했고

이렇게 등장한 것이 Virtual DOM 이다.

Virtual DOM이란? 🤔

Virtual DOM(가상돔)은 실제 DOM과 같은 내용을 담고 있는 복사본이다.

복사본은 실제 DOM이 아닌 JS 객체형태로 메모리 안에 저장되어 있다!

Virtual DOM 의 동작 과정 💁‍♂️

  1. DOM tree를 생성하고 렌더링 될때 브라우저에 렌더링 될때

    Virtual DOM 은 DOM 트리를 복사하여 복사본으로 가지고 있게 된다.

  1. 만약 DOM 을 조작하는 업데이트가 생겼을때

    변화가 완료된 새로운 Virtual DOM 을 만들게 된다.

    변화 이전 DOM 과 변화 후 DOM 두개를 가지고 있음

  2. 변화 이전 V-DOM 과 이후 V-DOM 을 비교하여 변화된 부분만을 확인하여

    실제로 변화된 부분만 실제 DOM 을 업데이트 한다.

결국 V-DOM 은 변화 내용을 캐싱하거나 버퍼링 (모아뒀다 한번에) 하는 동작으로 최적화 한다!

React 에서 Key prop

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가 바뀌고 모든 아이템이 리 렌더링 되기 때문이다.

profile
소통과 기록이 무기(Weapon)인 개발자

0개의 댓글