25 lines
5.6 KiB
Markdown
25 lines
5.6 KiB
Markdown
# [[React 렌더링 최적화|React 렌더링 최적화]]
|
|
|
|
## 📌 Brief Summary
|
|
React 렌더링 최적화는 애플리케이션의 불필요한 재렌더링을 방지하고 초기 로드 및 상호작용 속도를 향상시켜 사용자 경험을 개선하는 과정입니다 [1-3]. 기본적으로 부모 컴포넌트의 상태가 변경되면 모든 자식 컴포넌트가 다시 렌더링되는 폭포수(Cascade) 문제가 발생할 수 있습니다 [1, 2]. 이를 해결하기 위해 메모이제이션, [[React 18|React 18]]의 자동 배칭(Automatic Batching), 동시성 렌더링, 그리고 최근 도입된 [[React Compiler|React Compiler]]와 같은 기술을 활용하여 성능 병목을 최소화합니다 [4-8].
|
|
|
|
## 📖 Core Content
|
|
|
|
* **가상 DOM과 재조정([[Reconciliation|Reconciliation]]):** React는 DOM의 상태를 추상화한 **가상 DOM([[Virtual DOM|Virtual DOM]])**을 메모리에 유지하며, 상태가 변경될 때 이전 트리와 새로운 트리를 비교하여 실제 DOM에 필요한 최소한의 변경 사항만 업데이트합니다 [9-11]. 이 비교 과정에서는 **요소의 타입이 다르면 트리를 처음부터 다시 구축하고, 고유한 `key`를 사용하여 리스트 항목의 변경을 추적**하는 O(n) 복잡도의 휴리스틱 알고리즘을 사용합니다 [12-15].
|
|
* **Fiber 아키텍처와 동시성 렌더링([[Concurrent Rendering|Concurrent Rendering]]):** 기존의 동기식 렌더링이 메인 스레드를 차단하는 문제를 해결하기 위해 도입된 **Fiber 아키텍처는 렌더링 작업을 작은 '작업 단위(units of work)'로 나누어 처리**합니다 [16-18]. 중요도(Lane)에 따라 긴급한 상호작용을 우선 처리하고 무거운 작업은 양보하는 '타임 슬라이싱(Time-Slicing)'을 지원합니다 [17, 19, 20]. React 19의 `[[useTransition|useTransition]]` 및 `[[useDeferredValue|useDeferredValue]]` 훅을 사용하면 무거운 연산 중에도 메인 스레드를 차단하지 않고 UI 반응성을 유지할 수 있습니다 [5, 21, 22].
|
|
* **메모이제이션(Memoization):** 컴포넌트의 불필요한 재렌더링을 막기 위해 **`React.memo`, `useMemo`, `useCallback`을 사용하여 이전 계산 결과나 컴포넌트 상태를 캐싱**합니다 [4, 23, 24]. 그러나 매 렌더링마다 인라인 객체나 함수를 생성하면 참조 동등성([[Reference|Reference]] [[Equality|Equality]])이 깨져 메모이제이션이 무효화될 수 있습니다 [25-27]. 무분별한 메모이제이션은 오히려 비교 연산 및 메모리 오버헤드를 발생시키므로, 반드시 프로파일링을 통해 병목 지점을 찾은 후 선택적으로 적용해야 합니다 [23, 28].
|
|
* **자동 배칭(Automatic [[Batching|Batching]]):** React 18부터는 네이티브 이벤트 핸들러뿐만 아니라 **Promise, `setTimeout` 등 비동기 작업 내에서 발생하는 여러 상태 업데이트를 단일 재렌더링으로 묶어 처리**합니다 [6, 29-31]. 이를 통해 렌더링 횟수를 대폭 줄여 프레임 드롭을 방지할 수 있으며, 즉각적인 DOM 업데이트가 필요한 경우에는 `[[flushSync|flushSync]]` API를 사용하여 배칭에서 예외 처리할 수 있습니다 [32-34].
|
|
* **React Compiler를 통한 자동화:** React 19에 도입된 React Compiler는 빌드 타임에 코드의 추상 구문 트리(AST)를 분석하여 **필요한 곳에 자동으로 메모이제이션 경계를 삽입**합니다 [7, 35-38]. 개발자가 수동으로 의존성 배열(dependency array)을 관리할 필요성이 사라지며, 성능 향상은 물론 코드의 가독성과 유지보수성도 크게 개선됩니다 [7, 23, 39].
|
|
* **기타 구조적 최적화 기법:**
|
|
* **코드 스플리팅:** `React.lazy()`를 활용해 초기 번들 크기를 줄여 LCP(Largest Contentful Paint) 속도를 개선합니다 [40, 41].
|
|
* **가상화(Virtualization):** `react-window` 등을 사용하여 수천 개의 리스트 중 화면에 보이는 DOM 노드만 렌더링합니다 [42, 43].
|
|
* **DOM 노드 감소 및 상태 분리:** 불필요한 래퍼를 줄이는 React Fragment의 사용과, 렌더링 파급력을 최소화하기 위해 Context를 업데이트 빈도에 따라 분리하는 기법이 있습니다 [44-46].
|
|
* **[[React Server Components (RSC)|React Server Components (RSC]]:** 상호작용이 없는 정적 컴포넌트를 서버에서 전적으로 렌더링해 클라이언트 측으로 전송되는 [[JavaScript|JavaScript]] 페이로드를 원천적으로 차단합니다 [47-49].
|
|
|
|
## 🔗 Knowledge Connections
|
|
- **Related Topics:** [[Virtual DOM|Virtual DOM]], Reconciliation, Fiber Architecture, [[Automatic Batching|Automatic Batching]], React Compiler, [[React Server Components|React Server Components]]
|
|
- **Projects/Contexts:** [[프론트엔드 성능 최적화|프론트엔드 성능 최적화]], [[Core Web Vitals|Core Web Vitals]] 개선 전략, 대규모 단일 페이지 애플리케이션(SPA) 구축
|
|
- **Contradictions/Notes:** 기존에는 `useMemo`와 `useCallback`과 같은 수동 메모이제이션이 렌더링 최적화의 핵심으로 여겨졌으나, 새로운 React Compiler의 등장으로 이러한 수동 제어는 대부분 불필요해지거나 오히려 안티 패턴이 될 가능성이 제기되었습니다 [23, 39, 50]. 다만 서드파티 라이브러리의 불안정한 참조 반환 등 일부 엣지 케이스에서는 여전히 수동 메모이제이션이 이스케이프 해치(Escape hatch)로 사용됩니다 [51-53].
|
|
|
|
---
|
|
*Last updated: 2026-04-25* |