내가 사용하는 useCallBack, useMemo가 진짜 성능 최적화를 진행중인걸까?
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
앱 개발
대상자
- *React 개발자**
- 난이도: 중급*
- *대상자 설명**: 성능 최적화 기법을 학습하고 실제 적용을 고민하는 React 개발자. useMemo와 useCallback의 사용 시점, 과도한 사용의 위험성에 대한 이해가 필요함.
핵심 요약
useCallback
과useMemo
는 명확한 조건 없이 사용하면 오히려 성능 저하를 유발할 수 있음- 리액트 공식 문서는
useMemo
/useCallback
사용을React.memo
/useEffect
의존성 관리에 한정 권장 - 성능 최적화는 '정량적 기준'과 '병목 지점 확인'을 바탕으로 해야 하며, 무분별한 최적화는 유지보수 복잡도 증가
섹션별 세부 요약
1. 성능 최적화에 대한 고민과 의문
- useCallback
, useMemo
사용으로 불필요한 연산/리렌더링 줄일 수 있다는 기대
- "과도한 사용은 메모리 누수를 유발할 수 있다"는 우려
- "실제 문제가 발생했을 때 최적화를 도입하는 것이 더 나을까?"라는 고민
2. 실험 결과: 최적화가 성능 저하를 유발한 사례
- 최적화 적용 시 성능이 오히려 저하 (예: 최초 마운트 2.4ms → 1.6ms, 수량 증가 18.7ms → 16ms)
- 최적화 오버헤드(의존성 검사, 클로저 관리)가 실제 연산 비용(0.5ms)보다 높음
- 리액트 공식 문서 지침과 일치 (명확한 병목 없으면 최적화는 '추측에 의한 선제 조치')
3. 리액트 공식 문서의 `useCallback`/`useMemo` 사용 권장 사항
- useCallback
사용 조건:
React.memo
로 감싸진 컴포넌트에 props로 전달할 함수useEffect
의 의존성 배열에 포함된 함수
- useMemo
사용 조건:
- 눈에 띄게 느린 계산 (예: 배열 필터링, 정렬, 복잡한 객체 생성)
React.memo
로 감싸진 컴포넌트에 전달할 값useEffect
의 의존성 배열에 포함된 값
4. 성능 최적화 기준: 수치 기반 판단
- 시간 기준:
- 0.1ms 미만 → 최적화 불필요
- 1ms 이상 → 반드시 최적화 고려
- 데이터 크기 기준:
- 배열 길이 <20 → 최적화 보류
- 배열 길이 >100 → 적극적 최적화
- 연산 복잡도 기준:
- 단순 연산 (예:
.filter(item => item.active)
) → 최적화 효과 없음 - 복잡한 연산 (예:
.sort((a, b) => complexSortAlgorithm(a, b))
) → 최적화 고려
5. 실제 프로젝트에서의 성능 병목 지점
- 이미지 최적화 부족 (WebP 미지원, lazy loading 미적용)
- 불필요한 번들 크기 (lodash, moment 사용, tree shaking 미적용)
- 불필요한 API 호출 (리렌더링 시마다 fetch 요청)
- 과도한 useEffect
호출 (의존성 배열 미설정, side effect 제거 필요)
- 불필요한 리렌더 트리거 (Context memoization 누락, 상태 구조 비효율)
결론
useCallback
/useMemo
는React.memo
/useEffect
의존성 관리에 한정 사용- 성능 최적화는 '정량적 기준'과 '병목 지점 확인'을 바탕으로 해야 하며, 무분별한 최적화는 유지보수 복잡도 증가
- 실제 성능 병목은 이미지 최적화, 번들 크기, API 호출,
useEffect
관리, 리렌더 트리거 등에서 발생하는 경우가 많음