본문 바로가기
일상이 개발

React 앱 성능 병목 실전 분석: DevTools부터 Profiler까지 완전 정복

by 디어노미 2025. 4. 11.
반응형

🚀 React 앱에서 성능 병목 찾기: DevTools, why-did-you-render, Profiler 실전 분석

React로 앱을 개발하다 보면, 어느 순간 "앱이 느려졌다"는 피드백을 받게 됩니다. 하지만 문제는 "어디가 느린 건지"를 찾는 일이 생각보다 쉽지 않다는 점이죠. 성능 병목이 생기는 원인은 다양하지만, 이를 효과적으로 추적하고 최적화하려면 도구를 제대로 이해하고, 실전 상황에 적용할 수 있어야 합니다.

이번 글에서는 React 앱의 성능 병목을 파악하는 실전 도구 세 가지:

  • React DevTools
  • why-did-you-render
  • React Profiler

를 중심으로, 중급 개발자를 위한 분석 및 최적화 전략을 소개합니다.


1️⃣ React DevTools로 리렌더링 흐름 파악하기

React 개발자 도구(React Developer Tools)는 브라우저 확장 기능으로, 컴포넌트의 상태와 props, 렌더링 시점 등을 확인할 수 있습니다.

💡 주요 기능

  • 컴포넌트 트리 확인
  • props, state, hooks 상태 실시간 확인
  • 렌더링 시간 시각화 (Profiler 탭)

🧪 실전 활용법

  • 느려진 페이지에서 컴포넌트가 자주 리렌더링 되는 부분 확인
  • 부모 컴포넌트가 자식 컴포넌트를 과도하게 리렌더링하고 있는지 확인
  • React.memo, useMemo, useCallback이 잘 적용되고 있는지 확인

🔍 팁

DevTools의 Profiler 탭을 열고 "Record" → 앱을 조작 → "Stop recording" 하면 렌더링 시간과 횟수를 확인할 수 있습니다.


2️⃣ why-did-you-render로 불필요한 렌더링 감지

why-did-you-render는 React 컴포넌트가 불필요하게 리렌더링될 때 콘솔에 로그를 남겨주는 디버깅 도구입니다.

📦 설치

npm install @welldone-software/why-did-you-render

🔧 사용 설정 (React 17+)

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

if (process.env.NODE_ENV === 'development') {
  const whyDidYouRender = require('@welldone-software/why-did-you-render');
  whyDidYouRender(React, {
    trackAllPureComponents: true,
  });
}

ReactDOM.render(<App />, document.getElementById('root'));

🧠 주요 활용 포인트

  • props가 얕은 비교(shallow equal)로 달라졌는지 로그로 확인 가능
  • React.memo를 사용했지만 여전히 리렌더링 되는 컴포넌트를 추적 가능
  • useCallback이 없어서 함수가 새로 생성되어 리렌더링 되는 경우 탐지 가능

🔍 로그 예시

[why-did-you-render] Component <UserCard> re-rendered due to props changes:
[why-did-you-render] prev props: { user: { name: 'Tom' } }
[why-did-you-render] next props: { user: { name: 'Tom' } }

이 경우, 객체는 같아 보이지만 참조가 바뀌어 렌더링이 발생한 것입니다.


3️⃣ React Profiler API로 상세 분석

React Profiler는 DevTools의 기능이기도 하지만, 별도로 Profiler 컴포넌트를 사용해 앱 내부에서 렌더링 시간을 측정할 수 있습니다.

⛏ 사용 예시

import { Profiler } from 'react';

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime,
  interactions
) {
  console.log(`${id} - ${phase} - ${actualDuration}ms`);
}

<Profiler id="MyComponent" onRender={onRenderCallback}>
  <MyComponent />
</Profiler>

📊 분석 포인트

  • actualDuration: 렌더링에 실제 걸린 시간
  • baseDuration: 전체 렌더링 시간 (재사용 없이 풀 렌더할 경우)

이를 통해 특정 컴포넌트가 실제로 성능 병목을 유발하는지를 숫자로 확인할 수 있습니다.


🎯 최적화 전략 요약

문제 원인 탐지 도구 해결 방안

불필요한 리렌더링 why-did-you-render React.memo, useCallback, useMemo
깊은 props 비교 DevTools Profiler 데이터 구조 평탄화, memoization
너무 많은 상태 변화 DevTools / Profiler useReducer 또는 상태 분리
렌더링 시간 과다 Profiler API Suspense, Lazy Loading, 코드 스플리팅

🧩 번외: 렌더링 트리 분리

렌더링 병목을 줄이기 위해서는 컴포넌트의 렌더링 트리를 분리하는 것이 매우 효과적입니다. 예를 들어, 로딩 중인 부분과 상단 헤더처럼 변경되지 않는 영역을 분리하면, 전체 리렌더링을 방지할 수 있습니다.

<AppLayout>
  <Header /> {/* 변경 없음 */}
  <React.Suspense fallback={<Loading />}>
    <MainContent /> {/* 상태 변화 있음 */}
  </React.Suspense>
</AppLayout>

✅ 마무리

React 성능 문제는 "막연하게 느린 것 같다"고 접근하면 끝이 없습니다. 대신 정량적으로 측정하고, 시각적으로 분석하고, 도구로 확인하는 것이 실전 최적화의 핵심입니다.

DevTools, why-did-you-render, Profiler를 적극적으로 활용하면 렌더링 최적화 전략을 훨씬 더 명확하게 적용할 수 있습니다.

정확히 느려지는 지점을 알고 나면, React 앱은 얼마든지 빨라질 수 있습니다.

반응형