React 성능 최적화 완벽 가이드
1. 도입 – 학습 목표 및 필요성
🔗 관련 에러 해결 가이드
이 React 성능 최적화 완벽 가이드는 React 애플리케이션의 성능을 극대화하는 방법을 단계별로 학습하는 실전 튜토리얼입니다. 현대 웹 애플리케이션에서 성능은 사용자 경험의 핵심입니다. 느린 렌더링, 불필요한 리렌더링, 메모리 누수 등의 문제는 사용자 이탈률을 높이고 전환율을 낮춥니다. 본 가이드를 통해 React의 렌더링 메커니즘을 깊이 이해하고, memo, useMemo, useCallback 같은 최적화 도구를 실전에서 적용하는 방법을 익힐 수 있습니다. 초보 개발자도 쉽게 따라할 수 있도록 구성했으며, 실무에서 바로 활용 가능한 코드 예제와 함께 설명합니다.
2. 기본 개념 설명
React 성능 최적화를 이해하려면 먼저 React의 렌더링 프로세스를 알아야 합니다. React는 Virtual DOM을 사용해 실제 DOM 조작을 최소화하지만, 컴포넌트가 불필요하게 리렌더링되면 성능 저하가 발생합니다. 리렌더링은 state나 props가 변경될 때, 부모 컴포넌트가 리렌더링될 때 발생합니다. 최적화의 핵심은 불필요한 리렌더링을 방지하는 것입니다.
주요 최적화 기법은 다음과 같습니다:
- React.memo: 컴포넌트를 메모이제이션하여 props가 변경되지 않으면 리렌더링을 스킵합니다.
- useMemo: 계산 비용이 높은 값을 캐싱하여 재계산을 방지합니다.
- useCallback: 함수를 메모이제이션하여 자식 컴포넌트에 동일한 함수 참조를 전달합니다.
- Code Splitting: React.lazy와 Suspense를 사용해 필요한 코드만 로드합니다.
- Virtualization: 긴 리스트를 렌더링할 때 보이는 부분만 렌더링합니다.
3. 단계별 구현 가이드
단계 1: 성능 문제 진단하기
최적화를 시작하기 전에 먼저 문제를 파악해야 합니다. React DevTools의 Profiler 탭을 사용하면 각 컴포넌트의 렌더링 시간과 빈도를 측정할 수 있습니다.
개발 환경에서 아래 코드를 추가하면 렌더링을 추적할 수 있습니다:
// 개발 환경에서만 활성화
if (process.env.NODE_ENV === 'development') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React, {
trackAllPureComponents: true,
});
}
단계 2: React.memo로 컴포넌트 메모이제이션
자식 컴포넌트가 부모의 리렌더링에 영향받지 않도록 React.memo를 사용합니다. props가 변경되지 않으면 리렌더링을 건너뜁니다.
const ExpensiveComponent = React.memo(({ data }) => {
console.log('ExpensiveComponent 렌더링');
return (
{data.map(item => {item.name})}
);
});
객체나 배열을 props로 전달할 때는 사용자 정의 비교 함수를 제공할 수 있습니다:
const MemoizedComponent = React.memo(
({ user }) => {user.name},
(prevProps, nextProps) => {
return prevProps.user.id === nextProps.user.id;
}
);
단계 3: useMemo로 계산 최적화
복잡한 계산이나 필터링 작업을 메모이제이션하여 매 렌더링마다 재계산하지 않도록 합니다.
const FilteredList = ({ items, filterText }) => {
const filteredItems = useMemo(() => {
console.log('필터링 실행');
return items.filter(item =>
item.name.toLowerCase().includes(filterText.toLowerCase())
);
}, [items, filterText]);
return (
{filteredItems.map(item => - {item.name}
)}
);
};
단계 4: useCallback으로 함수 메모이제이션
자식 컴포넌트에 콜백 함수를 전달할 때 useCallback을 사용하면 불필요한 리렌더링을 방지합니다.
const ParentComponent = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const handleClick = useCallback(() => {
console.log('클릭 처리');
setCount(prev => prev + 1);
}, []); // 의존성 배열이 비어있으므로 함수는 한 번만 생성됨
return (
setText(e.target.value)} />
);
};
단계 5: Code Splitting 적용
React.lazy와 Suspense를 사용해 번들 크기를 줄이고 초기 로딩 속도를 개선합니다.
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
로딩 중...