8.3 KiB
8.3 KiB
Re-renders Optimization
📌 Brief Summary
Re-renders Optimization은 React 애플리케이션에서 불필요한 컴포넌트 업데이트를 최소화하여 성능, 반응성 및 사용자 경험을 향상시키는 과정입니다 [1, 2]. 주로 상태(state), 속성(props), 컨텍스트(context)의 변경으로 인해 발생하는 과도한 렌더링을 타겟으로 합니다 [3]. 이를 위해 수동 메모이제이션, 상태 관리 최적화, 가상화 기법, 그리고 React Compiler와 같은 최신 자동화 도구를 활용하여 병목 현상을 방지합니다 [4-6].
📖 Core Content
- 리렌더링의 원인과 성능적 영향: React 컴포넌트는 내부 상태(state) 변경, 속성(props) 변경, 구독 중인 컨텍스트(context) 값 변경, 혹은 부모 컴포넌트가 리렌더링될 때 업데이트됩니다 [3]. 불필요한 리렌더링이 누적되면 UI 반응성 저하, 메모리 사용량 증가, 상호작용성(TTI) 지연 등을 초래하며, 깊은 컴포넌트 트리에서는 스크립팅 시간을 30~60%까지 증가시킬 수 있습니다 [2].
- 수동 메모이제이션 (Manual Memoization):
React.memo()를 사용하면 props가 변경되지 않은 경우 이전 렌더링 결과를 재사용하여 렌더링 횟수를 30~50%가량 줄일 수 있습니다 [7, 8]. 이와 함께useCallback과useMemo훅을 사용하여 객체나 함수의 참조 동등성(Reference Equality)을 유지해야 자식 컴포넌트의 불필요한 렌더링을 막을 수 있습니다 [9, 10]. 단, 무분별한 사용은 비교 연산의 오버헤드를 발생시키므로 프로파일링을 통해 확인된 병목 구간에만 적용해야 합니다 [11, 12]. - 컨텍스트 최적화 (Context Optimization): React의 기본 Context API는 값의 일부만 변경되어도 해당 컨텍스트를 구독하는 모든 컴포넌트를 리렌더링합니다 [13, 14]. 이를 해결하기 위해 컨텍스트를 작은 도메인 단위로 쪼개거나 [15], 선택자(Selector)를 통해 상태의 특정 조각이 변경될 때만 리렌더링을 트리거하는 Zustand, Jotai 등의 외부 상태 관리 라이브러리를 사용하는 것이 권장됩니다 [16-18].
- React Compiler의 도입:
빌드 타임 최적화 도구인 React Compiler는 수동 메모이제이션(
useMemo,useCallback,React.memo) 코드를 작성하지 않아도 컴파일 단계에서 자동으로 캐싱 로직을 삽입합니다 [4, 19]. 컴포넌트 전체가 아닌 개별 JSX 요소 단위로 세분화하여 메모이제이션을 수행함으로써, 코드의 가독성을 높이고 불필요한 렌더링을 원천적으로 차단합니다 [19, 20]. - 렌더링 패턴 및 동시성 최적화:
수백 개 이상의 항목을 렌더링하는 대규모 리스트에서는 고유하고 안정적인
key속성을 부여하고, 화면에 보이는 항목만 렌더링하는 가상화(Windowing) 라이브러리(예:react-window)를 적용하여 DOM 오버헤드를 줄여야 합니다 [6, 21]. 또한 JSX 내부에 익명 함수를 직접 작성하면 매 렌더링마다 새로운 참조가 생성되므로 지양해야 합니다 [22, 23]. 부가적으로useTransition및useDeferredValue와 같은 동시성 기능을 활용해 무거운 업데이트를 지연시키고 사용자 입력에 대한 UI 반응성을 우선순위에 둘 수 있습니다 [24, 25].
🔗 Knowledge Connections
Related Concepts
-
- 연결 이유: 개발자가 수동으로 리렌더링을 최적화하던 기존 방식을 대체하여, 빌드 타임에 자동으로 메모이제이션을 적용하는 2025년 기준 핵심 기술이기 때문입니다 [4].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 컴포넌트 전체가 아닌 개별 JSX 요소와 연산이 어떻게 독립적으로 캐싱되는지의 원리와 서드파티 라이브러리 호환성 한계 [19, 26].
-
State Management (Zustand vs Context)
- 연결 이유: 불필요한 전체 리렌더링을 유발하는 Context API의 구조적 한계를 Zustand의 선택자(Selector) 패턴이 어떻게 극복하여 렌더링을 최적화하는지 설명하기 때문입니다 [13, 17].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 자주 변경되는 전역 상태 관리에서 React 렌더링 사이클 외부의 스토어가 어떻게 컴포넌트 렌더링을 정밀하게 제어하는지 [17, 27].
-
Memoization (useMemo, useCallback)
- 연결 이유: React의 얕은 비교(Shallow comparison) 특성을 극복하고 참조 동등성을 유지하여
React.memo와 결합한 리렌더링 최적화의 기반이 되기 때문입니다 [10]. - 이 개념을 통해 더 깊게 이해할 수 있는 부분: 무분별한 메모이제이션이 오히려 렌더링 비용보다 큰 성능 오버헤드를 유발하는 이유와 올바른 적용 조건 [11, 12].
- 연결 이유: React의 얕은 비교(Shallow comparison) 특성을 극복하고 참조 동등성을 유지하여
Deeper Research Questions
- React Compiler가 적용된 환경에서 기존
React.memo,useMemo,useCallback으로 작성된 수동 메모이제이션 코드는 어떤 방식으로 리팩토링되거나 공존해야 하는가? - Context API를 다수의 작은 도메인으로 분할하는 아키텍처와 Zustand를 도입하여 선택자를 사용하는 아키텍처 간의 렌더링 성능 및 유지보수성 트레이드오프는 무엇인가?
- 대규모 리스트에서 안정적인
key속성 부여와 가상화(Windowing) 기법을 함께 적용할 때, DOM 노드 관리와 메모리 가비지 컬렉션 측면에서 내부적으로 어떤 최적화가 발생하는가? - JSX 내 익명 함수 사용이 유발하는 참조 변경(Reference change) 문제를
useCallback외에 컴포넌트 외부 선언 방식 등으로 해결할 때 발생하는 상태 접근성 제약은 어떻게 극복할 수 있는가? useTransition과useDeferredValue를 활용한 동시성 렌더링(Concurrent rendering)이 리렌더링을 차단하지 않고 지연시킬 때, 무거운 연산이 메인 스레드를 점유하는 한계는 어떻게 보완할 수 있는가?
Practical Application Contexts
- Implementation: 무거운 컴포넌트나 자식에게 전달되는 함수/객체 prop에 대해
React.memo(),useCallback,useMemo를 선택적으로 적용하여 리렌더링을 방지합니다 [7, 10]. 대규모 리스트 구현 시react-window를 사용합니다 [6]. - System Design: 애플리케이션의 전역 상태를 설계할 때, 테마나 다국어처럼 변경이 적은 정적 데이터는 Context API를, 알림이나 장바구니처럼 빈번하게 변경되는 동적 데이터는 부분 구독(Selector)을 지원하는 외부 상태 라이브러리(Zustand 등)로 설계하여 렌더링 범위를 제한합니다 [18, 28, 29].
- Operation / Maintenance: React DevTools Profiler,
why-did-you-render라이브러리, Chrome DevTools Performance Tab을 활용하여 프로덕션 배포 전 및 운영 중에 불필요한 리렌더링과 그 원인을 지속적으로 측정하고 개선합니다 [30-32]. - Learning Path: React의 기본 렌더링 동작 원리(상태, props, 참조 동등성)를 먼저 학습하고 수동 메모이제이션의 비용을 이해한 뒤, 동시성 기능(Concurrent Features)과 React Compiler를 통한 자동화 최적화 패러다임으로 지식을 확장합니다 [5].
- My Project Relevance: 현재 유지보수하거나 새로 구축하는 React 프로젝트에서 성능 저하를 겪고 있다면, 익명 함수 인라인 작성 패턴을 수정하고, 불필요한 거대 Context를 분리하며, 식별 가능한 병목 지점에 프로파일링 기반의 메모이제이션을 적용해 즉각적인 성능 개선을 이룰 수 있습니다 [5, 15, 22].
Adjacent Topics
- Core Web Vitals (INP, FCP, TTI)
- 확장 방향: 프론트엔드 코드의 리렌더링 최적화가 실제 사용자의 체감 성능을 측정하는 지표(특히 Interaction to Next Paint)에 브라우저 레벨에서 어떤 영향을 미치는지 확장하여 조사합니다 [2, 33].
- Code Splitting & Lazy Loading
- 확장 방향: 컴포넌트 업데이트 시점(리렌더링)의 최적화뿐만 아니라, 컴포넌트 최초 로드 시점의 번들 크기를 줄여 초기 렌더링 성능을 극대화하는
React.lazy와 동적 임포트 기법을 함께 학습합니다 [34].
- 확장 방향: 컴포넌트 업데이트 시점(리렌더링)의 최적화뿐만 아니라, 컴포넌트 최초 로드 시점의 번들 크기를 줄여 초기 렌더링 성능을 극대화하는
Last updated: 2026-04-30