React 고급 기술 익히기 - 5편: Reconciliation과 렌더링 최적화
React는 UI 업데이트를 효율적으로 수행하기 위해 Reconciliation(재조정) 과정을 사용합니다. 이 과정에서 Virtual DOM을 활용하여 변경 사항을 감지하고, 최소한의 연산으로 실제 DOM을 업데이트합니다. 이번 글에서는 Reconciliation의 원리, Virtual DOM과 Diffing Algorithm, 성능 최적화 기법을 다룹니다. 🚀
1. Reconciliation(재조정)이란?
**Reconciliation(재조정)**은 React가 상태(State)나 Props가 변경될 때 어떤 부분을 업데이트해야 하는지 판단하는 과정입니다. 전체 UI를 다시 그리는 대신, 변경된 부분만 찾아 업데이트하여 성능을 최적화합니다.
✅ Reconciliation의 주요 특징
- 변경된 부분만 업데이트하여 성능 최적화
- Virtual DOM을 활용해 빠르게 변경 사항 감지
- Diffing Algorithm을 사용해 최소한의 연산 수행
2. Virtual DOM과 Reconciliation의 관계
2.1 Virtual DOM이란?
Virtual DOM은 React가 사용하는 메모리 내의 가상 UI 트리 구조입니다. UI 변경이 발생하면 React는 먼저 Virtual DOM을 업데이트한 후, 변경된 부분만 실제 DOM에 반영합니다.
✅ Virtual DOM의 장점
- 빠른 UI 업데이트 (전체 DOM을 갱신하는 기존 방식보다 성능이 우수함)
- 최소한의 DOM 변경 (변경 사항만 업데이트하여 불필요한 렌더링 방지)
- 일관된 개발 방식 제공
2.2 Virtual DOM vs. 실제 DOM 비교
특징Virtual DOM실제 DOM
업데이트 방식 | 변경된 부분만 감지 후 업데이트 | 전체 DOM을 다시 그림 |
성능 | 빠름 (최소한의 연산) | 느림 (DOM 조작 비용 큼) |
렌더링 방식 | Diffing Algorithm 적용 | 직접 요소 수정 |
3. React의 Reconciliation 과정
React는 UI를 업데이트할 때 다음과 같은 과정을 수행합니다.
3.1 새로운 Virtual DOM 생성
function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>현재 값: {count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
}
✅ count 값이 변경될 때 새로운 Virtual DOM이 생성됩니다.
3.2 Diffing Algorithm 적용
- React는 이전 Virtual DOM과 새로운 Virtual DOM을 비교하여 변경된 부분을 찾습니다.
- 예를 들어 <p>현재 값: 0</p>가 <p>현재 값: 1</p>로 변경되었다면, <p> 태그만 업데이트합니다.
3.3 변경 사항을 실제 DOM에 적용
- React는 Diffing Algorithm을 통해 감지된 변경된 부분만 실제 DOM에 업데이트합니다.
- 동일한 태그라면 속성만 변경, 다른 태그라면 새로 생성하는 방식으로 최적화됩니다.
4. Reconciliation 성능 최적화 전략
4.1 React.memo 사용
React.memo를 활용하면 불필요한 렌더링을 방지할 수 있습니다.
const ChildComponent = React.memo(({ value }) => {
console.log('렌더링 발생!');
return <div>{value}</div>;
});
function ParentComponent() {
const [count, setCount] = React.useState(0);
return (
<div>
<ChildComponent value="React.memo 활용" />
<button onClick={() => setCount(count + 1)}>Increase Count</button>
</div>
);
}
✅ React.memo를 사용하면 props가 변경되지 않는 한 컴포넌트가 재렌더링되지 않습니다.
4.2 useCallback으로 함수 메모이제이션
React는 컴포넌트가 리렌더링될 때 함수가 새로 생성됩니다. 이를 방지하려면 useCallback을 사용해 함수 인스턴스를 유지할 수 있습니다.
const Button = React.memo(({ onClick }) => {
console.log('Button 렌더링');
return <button onClick={onClick}>Click Me</button>;
});
export default function App() {
const [count, setCount] = React.useState(0);
const handleClick = React.useCallback(() => {
console.log('Button Clicked');
}, []);
return (
<div>
<Button onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>Increase Count</button>
</div>
);
}
✅ useCallback을 사용하면 함수가 불필요하게 다시 생성되지 않습니다.
4.3 Key 값을 활용한 리스트 최적화
React는 Key 값을 기반으로 변경 사항을 감지합니다. Key 값이 없거나 불안정하면 성능이 저하될 수 있습니다.
{items.map((item) => (
<li key={item.id}>{item.name}</li> // ✅ 추천!
))}
✅ Key는 항상 고유한 값을 사용해야 합니다.
5. React Reconciliation 정리
최적화 기법 | 설명 |
React.memo | 같은 props라면 컴포넌트의 재렌더링을 방지 |
useCallback | 함수의 메모이제이션을 통해 불필요한 함수 생성 방지 |
Key 사용 | 리스트 렌더링 시 변경 사항을 효율적으로 감지 |
결론
- **Reconciliation(재조정)**은 React가 변경 사항을 감지하고 최소한의 DOM 업데이트만 수행하는 과정입니다.
- Virtual DOM과 Diffing Algorithm을 활용하여 성능을 최적화합니다.
- React.memo, useCallback, Key 값 활용을 통해 불필요한 렌더링을 방지할 수 있습니다.