개발/React

[중급반] Step 1-2. Hook을 활용한 메모이제이션과 최적화

ophelisis 2025. 12. 15. 13:54
반응형

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는 두 번째 인수로 커스텀 비교 함수를 받을 수 있습니다.

JavaScript
 
// 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-1 단계에서 리렌더링 문제가 발생했던 예제(리스트 등)를 준비합니다.
  2. React.memo 적용: 불필요하게 리렌더링되던 자식 컴포넌트에 React.memo를 적용해 보세요.
  3. useCallback 적용: 자식에게 함수 형태의 Props(예: onClickHandler)를 넘길 때, 부모 컴포넌트에서 useCallback을 적용하여 리렌더링이 확실히 줄어드는지 DevTools Profiler로 확인하고 결과를 비교하세요.
반응형