React 렌더링 원리를 이해했다면, 이제 불필요한 리렌더링 전파를 막는 '메모이제이션(Memoization)' 도구를 활용할 차례입니다. 중급 개발자에게 useMemo, useCallback, React.memo는 선택이 아닌 필수입니다.
이 Hook들을 정확히 이해하고, 성능 향상에 기여하는 '적절한 시점'을 파악하는 것이 중요합니다.
1. 🚀 useMemo: 무거운 계산 결과를 캐싱 (값의 메모이제이션)
useMemo는 **'값을 기억(Memoize)하는 Hook'**입니다. 복잡한 연산 결과를 캐싱하여, 의존성 배열(deps)이 변경되지 않는 한 해당 연산을 다시 실행하지 않고 이전에 캐싱된 값을 재사용합니다.
| 속성 | 설명 |
| 목적 | 시간이 오래 걸리는 계산의 결과를 저장하고 재사용하여 렌더링 속도 개선. |
| 문법 | const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); |
| 적정 사용 시점 | 수백, 수천 개의 데이터를 필터링/정렬하는 등 CPU를 많이 사용하는 연산 결과가 필요할 때. |
📝 주의 사항: 과도한 사용은 독!
useMemo는 캐싱된 값을 메모리에 저장하므로, 과도하게 사용하면 메모리 사용량이 늘어나 오히려 메모리 할당 오버헤드가 발생하여 성능이 저하될 수 있습니다. 정말로 복잡하고 느린 계산에만 사용해야 합니다.
2. ⚡ useCallback: 함수 자체를 캐싱 (함수의 메모이제이션)
useCallback은 **'함수를 기억하는 Hook'**입니다. 의존성 배열(deps)이 변경되지 않는 한, 컴포넌트가 리렌더링되어도 함수를 새로 생성하지 않고 이전에 생성된 **동일한 함수 참조(Reference)**를 재사용합니다.
| 속성 | 설명 |
| 목적 | 불필요한 함수 재생성을 막아, 자식 컴포넌트의 불필요한 리렌더링을 방지하는 데 주로 사용됩니다. |
| 문법 | const memoizedHandler = useCallback(() => { /* ... */ }, [dependency]); |
| 적정 사용 시점 | React.memo로 감싼 자식 컴포넌트에 Props로 함수를 전달할 때. (함수 참조가 달라지면 React.memo가 작동하지 않기 때문) |
3. 🛡️ React.memo: 컴포넌트의 리렌더링 제어
React.memo는 함수형 컴포넌트의 리렌더링을 제어하는 고차 컴포넌트(HOC)입니다. Props가 변경되지 않으면 React.memo가 리렌더링 자체를 건너뛰도록 지시합니다.
| 속성 | 설명 |
| 목적 | 부모의 리렌더링 때문에 Props가 변경되지 않은 자식 컴포넌트가 불필요하게 렌더링되는 것을 방지합니다. |
| 작동 방식 | Props의 **얕은 비교(Shallow Comparison)**를 수행합니다. (객체나 배열 내부 값이 아닌, 참조(Reference)만 비교) |
| 필수 조합 | 자식 컴포넌트가 React.memo로 최적화되었다면, 부모가 전달하는 함수 Props는 반드시 **useCallback**으로 감싸줘야 효과가 있습니다. |
📝 커스텀 비교 함수 (Custom Comparison)
React.memo는 두 번째 인수로 커스텀 비교 함수를 받을 수 있습니다.
// props가 같으면 true를 반환하여 리렌더링을 막습니다.
React.memo(MyComponent, (prevProps, nextProps) => {
return prevProps.userId === nextProps.userId;
});
이 함수를 사용하면 기본 얕은 비교 방식으로는 최적화하기 어려운, 객체 속성의 특정 값만 비교하도록 정교하게 제어할 수 있습니다.
4. 🔗 성능 최적화의 '삼각편대' 활용 전략
세 가지 Hook은 독립적으로 작동하기보다 서로 협력하여 시너지를 냅니다.
| 상황 | 문제점 | 해결 방안 |
| (A) 연산이 느릴 때 | 컴포넌트 내부의 복잡한 연산이 매번 리렌더링 시마다 다시 실행됨. | **useMemo**를 사용하여 연산 결과 캐싱. |
| (B) 함수 Props 전달 시 | 부모가 리렌더링 될 때마다 함수 Props의 참조가 바뀌어, 자식(React.memo 적용)이 불필요하게 리렌더링됨. | 부모 컴포넌트에서 함수 Props를 **useCallback**으로 감싸서 전달. |
| (C) 자식 컴포넌트 보호 | 부모의 리렌더링이 자식에게까지 전파됨. | 자식 컴포넌트를 **React.memo**로 감싸서 Props 변경 여부를 체크하게 함. |
핵심: **useCallback**과 **React.memo**는 성능 최적화의 기본 세트입니다.
🛠️ 1-2 실습 미션 (Challenge)
- 성능 분석: 1-1 단계에서 리렌더링 문제가 발생했던 예제(리스트 등)를 준비합니다.
- React.memo 적용: 불필요하게 리렌더링되던 자식 컴포넌트에 React.memo를 적용해 보세요.
- useCallback 적용: 자식에게 함수 형태의 Props(예: onClickHandler)를 넘길 때, 부모 컴포넌트에서 useCallback을 적용하여 리렌더링이 확실히 줄어드는지 DevTools Profiler로 확인하고 결과를 비교하세요.
'개발 > React' 카테고리의 다른 글
| [중급반] Step 2-1. Redux Toolkit (RTK) 심화 마스터 (0) | 2025.12.15 |
|---|---|
| [중급반] Step 1-3. 고급 렌더링 제어 및 지연 로딩 (0) | 2025.12.15 |
| [중급반] Step 1-1. React 렌더링 원리 및 Reconciliation 이해 (0) | 2025.12.15 |
| [초급반] Step 10. 라우팅과 페이지 이동: react-router-dom 사용법 (0) | 2025.12.01 |
| [초급반] Step 9. 데이터 가져오기 (Fetching): React와 API 통신하기 (0) | 2025.12.01 |