React 성능 최적화: useMemo와 React.memo 제대로 이해하기
⚡️ 웹 성능 최적화와 React 내부 최적화
- 웹 서비스의 성능을 개선하기 위한 모든 행위를 ‘최적화(Optimization)’라고 한다.
- 아주 단순한 것부터 복잡한 기법까지 다양한 방식이 있다.
🛠️ 일반적인 웹 서비스 최적화 방법
- 서버 응답 속도 개선 (예: 캐싱, DB 쿼리 최적화)
- 이미지, 폰트, JS/CSS 등의 정적 자산 로딩 최적화
- 네트워크 요청 최소화 및 병렬화
- 코드 스플리팅, Lazy Loading 등 클라이언트 사이드 최적화
🛠️ React 앱 내부 최적화 방법
- 컴포넌트 내부의 불필요한 연산 방지
- 불필요한 함수 재생성 방지
- 불필요한 컴포넌트 리렌더링 방지
- 이러한 부분에서
useMemo, useCallback, React.memo 같은 API가 사용된다.
📦 useMemo를 통한 연산 최적화
📌 useMemo란?
- 메모이제이션(Memoization) 기법을 활용한 React 훅
- 값이 변하지 않는 한, 계산을 다시 하지 않고 이전 결과를 재사용
useCallback은 useMemo의 함수 버전으로, 콜백 함수를 메모이제이션할 때 사용된다.
📘 메모이제이션(Memoization)이란?
- 동일한 계산에 대해 이전 결과를 저장해 재사용하는 최적화 기법
- 대표적인 활용 예: 피보나치 수열, 동적 계획법 등 반복 계산이 많은 알고리즘
✅ 사용 예시
const expensiveValue = useMemo(() => {
return computeExpensiveValue(input);
}, [input]);
input이 바뀌지 않으면 computeExpensiveValue는 다시 호출되지 않고, 이전 결과를 그대로 반환
📦 React.memo를 통한 렌더링 최적화
📌 React.memo란?
- 고차 컴포넌트(HOC)로, 함수형 컴포넌트를 메모이제이션하여,
props가 변경되지 않으면 리렌더링을 방지
- 얕은 비교(Shallow Comparison)를 통해 props를 비교
✅ 사용 예시
const MyComponent = ({ value }) => {
return <div>{value}</div>;
};
const MemoizedComponent = React.memo(MyComponent);
value가 이전과 동일하면 MemoizedComponent는 리렌더링되지 않음
💡 동작 방식과 주의 사항
React.memo는 기본적으로 얕은 비교만 수행
- 객체, 배열, 함수 등은 새로운 참조일 경우 내용이 같아도 리렌더링 발생
props 비교를 커스터마이징하려면 두 번째 인수로 비교 함수를 제공
const areEqual = (prevProps, nextProps) => {
return prevProps.value === nextProps.value;
};
const Memoized = React.memo(MyComponent, areEqual);
- 리렌더링 비용이 큰 컴포넌트에만 사용하는 것이 좋다.
→ 무분별한 사용은 오히려 불필요한 비교 비용으로 성능을 악화시킬 수 있음
- 클래스 컴포넌트에는 사용할 수 없음 (함수형 컴포넌트 전용)
📘 고차 컴포넌트(Higher-Order Component, HOC)
- 컴포넌트를 인수로 받아 새로운 컴포넌트를 반환하는 함수
- 컴포넌트 로직을 재사용하거나, 기능을 확장할 때 사용
React.memo, withRouter, connect(mapStateToProps) 등이 대표적인 예시
✅ 정리
useMemo는 값의 재계산 방지
React.memo는 컴포넌트의 불필요한 리렌더링 방지
- 최적화 도구는 필요할 때 사용해야 하며, 과도한 사용은 성능 저하를 유발할 수 있다