[React] 리액트가 리렌더링시 기존과 바뀐부분을 알아내는 방법은?

eastZoo·2024년 5월 22일

React

목록 보기
13/15

0️⃣ 방법은!?

🐸 : React가 리렌더링 시 기존과 바뀐 부분을 알아내는 방법은
주로 Virtual DOM디프 알고리즘(diffing algorithm)을 통해 이루어져요.
이 과정은 다음과 아래와 같이 이루어져요


1. Virtual DOM의 생성

React 컴포넌트는 상태props가 변경될 때마다
새로운 Virtual DOM을 생성합니다. 이 Virtual DOM은 메모리 내에서 가볍게 생성되며,
기존의 Virtual DOM비교 하기 위한 참조용으로 사용됩니다.


2. Diff 알고리즘

React는 상태변화에 따라 생성된 새로운 Virtual DOM이전 Virtual DOM을 비교하여 차이점을 찾습니다.
이 과정을 디핑(diffing) 이라고 부르며, 효율적이고 빠르게 차이점을 찾아내기 위해 최적화된 알고리즘을 사용합니다.

💡 Key Steps in Diff Algorithm
1. Element Type 비교 : 동일한 위치에 있는 두 요소의 타입을 비교합니다. 타입이 다르면 이전 요소를 삭제하고 새로운 요소로 교체합니다.

2. 속성 비교: 요소의 속성을 비교하여 변경된 속성만 업데이트합니다.

3. Key 비교: 리스트 구조에서 각 자식 요소에 키(key) 속성을 부여하여 요소 간의 이동, 추가, 제거 등을 효율적으로 처리합니다.


3. 실제 DOM 업데이트

Virtual DOM과 실제 DOM의 차이점을 찾은 후, React는 변경된 부분만 실제 DOM에 업데이트합니다. 이를 통해 최소한의 DOM 조작으로 성능을 최적화합니다.



💬 예시

다음은 React가 디프 알고리즘을 사용하는 방법을 설명하는 예제입니다.

import React, { useState } from 'react';

const TodoList = () => {
  const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);

  const addItem = () => {
    setItems([...items, `Item ${items.length + 1}`]);
  };

  return (
    <div>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      <button onClick={addItem}>Add Item</button>
    </div>
  );
};

export default TodoList;

📑 위 코드의 디프 알고리즘 과정 해설

  1. 상태 또는 props 변경
    사용자가 Add Item 버튼을 클릭하면 addItem 함수가 호출되어 상태 items에 새로운 항목을 추가합니다. setItems는 새로운 상태 배열을 설정하고 컴포넌트가 리렌더링되도록 트리거합니다.
    👇

  2. 새로운 Virtual DOM 생성
    상태가 변경되면 React는 컴포넌트를 다시 호출하여 새로운 Virtual DOM 트리를 생성합니다. 이 예제에서는 새로운 리스트 항목이 추가된 Virtual DOM이 생성됩니다.

  • 이전 Virtual DOM:
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>
<button>Add Item</button>
  • 새로운 Virtual DOM:
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
</ul>
<button>Add Item</button>

👇

  1. Virtual DOM 비교 (디프 알고리즘)
    React는 이전 Virtual DOM과 새로운 Virtual DOM을 비교하여 변경된 부분을 찾아냅니다. React의 디프 알고리즘은 주로 두 가지 규칙을 사용합니다:
  • 다른 타입의 요소들은 다르게 취급 : 두 요소의 타입이 다르면 이전 요소를 제거하고 새로운 요소를 추가합니다.

  • 동일한 타입의 요소들은 속성과 자식을 비교 : 두 요소의 타입이 같으면 속성과 자식 요소들을 재귀적으로 비교합니다.

리스트 비교:

  1. ul 요소는 동일하므로, 자식 요소들을 비교합니다.
  2. li 요소 1, 2, 3은 동일하므로, 텍스트와 키를 비교합니다.
  3. li 요소 4는 새로운 요소이므로 추가됩니다.
  4. 실제 DOM 업데이트
    디프 알고리즘을 통해 변경된 부분만 실제 DOM에 반영합니다. 이 예제에서는 ul 요소에 새로운 li 요소 4가 추가됩니다. 나머지 요소들은 변경되지 않으므로 그대로 유지됩니다.


🐸 번외 -> 최적화: React.memo

🚩 다음 포스팅에서 만날 키워드 : React.memo, memoization

리렌더링 최적화를 위해 React.memo를 사용할 수 있습니다.
이는 props가 변경되지 않으면 컴포넌트를 리렌더링하지 않습니다.

import React, { useState } from 'react';

const TodoList = React.memo(() => {
  const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);

  const addItem = () => {
    setItems([...items, `Item ${items.length + 1}`]);
  };

  return (
    <div>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      <button onClick={addItem}>Add Item</button>
    </div>
  );
});

export default TodoList;

💡 : React.memo를 사용하면, 부모 컴포넌트가 리렌더링되더라도 props가 변경되지 않는 한 Counter 컴포넌트는 리렌더링되지 않습니다.
이를 통해 불필요한 리렌더링을 방지하고 성능을 최적화할 수 있습니다.



1️⃣ 결론

React는 Virtual DOM과 디프 알고리즘을 사용하여 상태나 props가 변경될 때마다 효율적으로 DOM을 업데이트합니다.
이를 통해 성능을 최적화하고 빠르게 UI를 업데이트할 수 있습니다.



끝🙋🏻

💬 : 위 내용에대해 더 궁금한점이 있거나,
틀린내용이 있거나
질문이 있다면 댓글로 달아주세요.!!

profile
Looking for an answer to what is a developer🧐;

0개의 댓글