React 앱에서 성능 병목 찾기: DevTools, why-did-you-render, Profiler 실전 분석
⚙️ React 앱에서 성능 병목 찾기
DevTools, why-did-you-render, Profiler 실전 분석 가이드
React로 앱을 개발하다 보면, 어느 순간 앱이 “느려졌다”고 느끼는 순간이 옵니다. 특히 페이지 전환, 리스트 렌더링, Form 조작 등 사용자 인터랙션이 많아질수록 성능 병목은 명확해집니다.
하지만 그 "느려짐"이 정확히 어디서 오는지 모르면 최적화는 막막하기만 하죠.
이번 글에서는 React 앱의 병목을 실전에서 어떻게 탐지하고 분석하며 개선할 수 있는지를 다음 도구들을 중심으로 소개합니다:
- React DevTools Profiler
- why-did-you-render 라이브러리
- Chrome DevTools + 실제 UX 테스트 전략
🚨 성능 병목이란? 왜 생길까?
React 앱의 성능 병목은 주로 다음 3가지에서 발생합니다:
- 불필요한 리렌더링
상태 변화가 직접 연관 없는 컴포넌트까지 영향을 주는 경우 - 복잡한 연산을 매 렌더마다 반복
예: 무거운 계산, 정렬, 필터링이 컴포넌트 내에서 실행됨 - 비효율적인 컴포넌트 구조
모든 UI가 하나의 상위 컴포넌트에 묶여있거나, props drilling이 과한 경우
🛠 React DevTools Profiler로 분석하기
React DevTools의 Profiler 탭은 브라우저 확장으로 설치할 수 있습니다.
크롬에서 설치 후, React 앱을 열면 "Profiler" 탭이 보입니다.
🔍 사용법
- Profiler 탭 클릭 → ‘Record’ 버튼 클릭
- 앱에서 느려지는 액션 수행 (예: 버튼 클릭, 리스트 필터링 등)
- 다시 Profiler 탭 → ‘Stop’ 클릭 → 분석 결과 확인
📈 분석 포인트
- 렌더링 시간: 어떤 컴포넌트가 몇 ms 걸렸는가?
- 리렌더 횟수: 같은 컴포넌트가 너무 자주 리렌더되는가?
- 렌더 트리 흐름: 부모-자식 간 렌더링 연쇄가 발생했는가?
✅ 활용 팁
- 너무 자주 리렌더되는 컴포넌트는
React.memo
,useMemo
,useCallback
으로 묶을 후보 - 무거운 리스트 컴포넌트는 virtual scroll 도입 검토
- 상태 변경이 예상보다 많은 컴포넌트까지 퍼지지 않는지 확인
🧠 why-did-you-render로 리렌더링 감지하기
불필요한 리렌더링은 병목의 대표 원인입니다.why-did-you-render
는 이런 리렌더를 콘솔에서 자동으로 알려주는 강력한 도구입니다.
🔧 설치 및 세팅
npm install @welldone-software/why-did-you-render
_app.tsx 또는 _app.js에서 설정:
{`if (process.env.NODE_ENV === 'development') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React, {
trackAllPureComponents: true,
});
}`}
컴포넌트에서 리렌더 감지 활성화:
{`const MyComponent = React.memo(({ title }) => {
return
{title};
});
MyComponent.whyDidYouRender = true;`}
📝 콘솔 로그 예시
[why-did-you-render] MyComponent re-rendered because props.title changed shallowly.
- props나 context 변경으로 인한 리렌더
useCallback
,useMemo
를 사용하지 않아 함수나 객체 참조가 매번 변경됨
🧪 DevTools + 실측 벤치마크 테스트
UI는 “수치”보다 실제 “느낌”이 중요할 때도 있습니다.
브라우저 DevTools → Performance 탭에서 아래 항목을 체크하세요:
🔍 확인 포인트
- Layout Shift: 요소 이동으로 화면 흔들림 발생 여부
- Long Tasks: 메인 스레드가 50ms 이상 점유된 작업
- Scripting Time: JavaScript 실행 시간이 과도한 구간
- Paint 시간: 브라우저가 화면을 다시 그리는 시간
이 도구는 React 외에도 전체 렌더링 체인을 포함해 분석하므로, 외부 라이브러리 병목도 감지 가능합니다.
🛠 실전 최적화 전략 정리
1️⃣ React.memo로 리렌더 방지
{`const Item = React.memo(({ name }) => {
return
{name};
});`}
props가 바뀌지 않으면 렌더 스킵
함수/객체는 참조가 바뀌면 리렌더 → useCallback
필수
2️⃣ useCallback, useMemo로 참조 유지
{`const handleClick = useCallback(() => {
doSomething();
}, []);
const value = useMemo(() => computeValue(), [dependency]);`}
3️⃣ key 속성은 안정적으로 관리
{`// ❌ Bad
{items.map(item => )}
// ✅ Good
{items.map(item => )}`}
4️⃣ 조건부 렌더링 최소화
{`// ❌
{condition && }
// ✅
const MemoizedBigComponent = useMemo(() => , []);
return condition ? MemoizedBigComponent : null;`}
5️⃣ Lazy Load + Dynamic Import
{`import dynamic from 'next/dynamic';
const HeavyChart = dynamic(() => import('./Chart'), { ssr: false });`}
초기 로딩 속도 향상에 효과적입니다.
✅ 마무리 요약
React 앱이 “느려진다”는 느낌은 거의 대부분 렌더링 구조의 문제입니다.
DevTools, why-did-you-render, Profiler 등의 도구를 적극 활용하면 병목 지점을 빠르게 진단할 수 있습니다.
🔑 핵심 요약
항목 | 전략 |
---|---|
리렌더 추적 | why-did-you-render 도입 |
병목 시간 분석 | React Profiler, Performance 탭 사용 |
최적화 기법 | React.memo, useMemo, useCallback |
큰 컴포넌트 로딩 최적화 | dynamic import, lazy loading |
상태 최적화 | 불필요한 props 전달 줄이기, 상태 최소화 |
성능 최적화는 한 번에 끝나지 않습니다.
작은 병목을 발견하고 고쳐가는 반복적인 흐름 속에서 더 좋은 React 앱을 만들어갈 수 있어요. 🚀