5.6 KiB
5.6 KiB
React 렌더링 최적화
📌 Brief Summary
React 렌더링 최적화는 애플리케이션의 불필요한 재렌더링을 방지하고 초기 로드 및 상호작용 속도를 향상시켜 사용자 경험을 개선하는 과정입니다 [1-3]. 기본적으로 부모 컴포넌트의 상태가 변경되면 모든 자식 컴포넌트가 다시 렌더링되는 폭포수(Cascade) 문제가 발생할 수 있습니다 [1, 2]. 이를 해결하기 위해 메모이제이션, React 18의 자동 배칭(Automatic Batching), 동시성 렌더링, 그리고 최근 도입된 React Compiler와 같은 기술을 활용하여 성능 병목을 최소화합니다 [4-8].
📖 Core Content
- 가상 DOM과 재조정(Reconciliation): React는 DOM의 상태를 추상화한 **가상 DOM(Virtual DOM)**을 메모리에 유지하며, 상태가 변경될 때 이전 트리와 새로운 트리를 비교하여 실제 DOM에 필요한 최소한의 변경 사항만 업데이트합니다 [9-11]. 이 비교 과정에서는 요소의 타입이 다르면 트리를 처음부터 다시 구축하고, 고유한
key를 사용하여 리스트 항목의 변경을 추적하는 O(n) 복잡도의 휴리스틱 알고리즘을 사용합니다 [12-15]. - Fiber 아키텍처와 동시성 렌더링(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 Equality)이 깨져 메모이제이션이 무효화될 수 있습니다 [25-27]. 무분별한 메모이제이션은 오히려 비교 연산 및 메모리 오버헤드를 발생시키므로, 반드시 프로파일링을 통해 병목 지점을 찾은 후 선택적으로 적용해야 합니다 [23, 28]. - 자동 배칭(Automatic 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): 상호작용이 없는 정적 컴포넌트를 서버에서 전적으로 렌더링해 클라이언트 측으로 전송되는 JavaScript 페이로드를 원천적으로 차단합니다 [47-49].
- 코드 스플리팅:
🔗 Knowledge Connections
- Related Topics: Virtual DOM, Reconciliation, Fiber Architecture, Automatic Batching, React Compiler, React Server Components
- Projects/Contexts: 프론트엔드 성능 최적화, Core Web Vitals 개선 전략, 대규모 단일 페이지 애플리케이션(SPA) 구축
- Contradictions/Notes: 기존에는
useMemo와useCallback과 같은 수동 메모이제이션이 렌더링 최적화의 핵심으로 여겨졌으나, 새로운 React Compiler의 등장으로 이러한 수동 제어는 대부분 불필요해지거나 오히려 안티 패턴이 될 가능성이 제기되었습니다 [23, 39, 50]. 다만 서드파티 라이브러리의 불안정한 참조 반환 등 일부 엣지 케이스에서는 여전히 수동 메모이제이션이 이스케이프 해치(Escape hatch)로 사용됩니다 [51-53].
Last updated: 2026-04-25