반응형
1. useMemo란? — 기본 개념
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- 의존성 배열([a, b])의 값이 변경될 때만 계산 함수 실행
- 변경되지 않으면 이전 계산 결과 재사용 (메모이제이션)

주의: useMemo는 힌트(hint)일 뿐 보장 X
React는 메모리 압박 시 의존성 불변이라도 재계산 가능
→ 순수 함수(동일 입력 → 동일 출력)만 사용해야 안전
2. 실무에서 흔한 3대 오용 사례
|
1. 단순 값 할당
|
오버헤드 > 이득
|
useMemo제거
|
|
2. 객체/배열 무분별 생성
|
참조 불일치로 리렌더 폭증
|
useMemo필수
|
|
3. 의존성 누락/과잉
|
stale closure / 불필요한 재계산
|
eslint-plugin-react-hooks
|
사례 1: 단순 문자열 생성 (비추천)
// ❌ 오용: 계산 비용이 낮음
const title = useMemo(() => `${menuName} - ${system}`, [menuName, system]);
// ✅ 개선: 일반 변수
const title = `${menuName} - ${system}`;
사례 2: 객체/배열 생성 (권장)
// ❌ 오용: 매 렌더링 시 새 객체 생성 → 자식 컴포넌트 불필요 리렌더
const contextValue = {
user: currentUser,
logout: handleLogout,
};
// ✅ 개선: useMemo로 참조 안정화
const contextValue = useMemo(() => ({
user: currentUser,
logout: handleLogout,
}), [currentUser, handleLogout]);
사례 3: 의존성 실수 (위험)
// ❌ 오용: currentUser 누락 → stale closure
const userInfo = useMemo(() => ({
id: currentUser.id, // currentUser 변경 시 갱신 안 됨!
displayName: getDisplayName(currentUser),
}), []); // ⚠️ 의존성 누락
// ✅ 개선: 모든 의존성 명시
const userInfo = useMemo(() => ({
id: currentUser.id,
displayName: getDisplayName(currentUser),
}), [currentUser]); // ✅
부록: useMemo vs useCallback 비교
|
|
USEMEMO
|
USECALLBACK
|
|
용도
|
값 메모이제이션
|
함수 메모이제이션
|
|
사용법
|
useMemo(() => value, deps)
|
useCallback(() => fn, deps)
|
|
동등 표현
|
useMemo(() => fn, deps)
|
useMemo(() => fn, deps)
|
|
주요 시나리오
|
객체/배열/계산된 값
|
이벤트 핸들러, 콜백 전달
|
핵심:
- useCallback(fn, deps) ≡ useMemo(() => fn, deps)
- 객체 생성 → useMemo
- 함수 생성 → useCallback
|
useMemo
|
계산된 값의 메모이제이션
|
캐시, 성능 최적화, 참조 안정화
|
|
useRef
|
값 저장소(리렌더 X)
|
DOM 참조, 이전 값, 타이머
|
|
useState
|
업데이트 가능한 상태
|
사용자 입력, UI 상태
|
|
useCallback
|
함수 메모이제이션
|
콜백 전달, 자식 컴포넌트 최적화
|
React에서의 메모이제이션 — useMemo
React는 컴포넌트가 리렌더될 때마다 모든 코드를 다시 실행합니다.
문제는 계산 비용이 큰 로직이 매번 재실행된다는 것!
❌ 문제 상황
function UserList({ users }) {
// 🚨 매 리렌더링 시 10,000건 정렬 → 100ms 지연!
const sortedUsers = users
.filter(u => u.isActive)
.sort((a, b) => a.name.localeCompare(b.name));
return (
<ul>
{sortedUsers.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
✅ 해결: useMemo로 메모이제이션
function UserList({ users }) {
// ✅ users 변경 시만 재계산
const sortedUsers = useMemo(() => {
console.log("정렬 실행!"); // users 변경 시만 출력
return users
.filter(u => u.isActive)
.sort((a, b) => a.name.localeCompare(b.name));
}, [users]); // 의존성: users
return (
<ul>
{sortedUsers.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
동작 원리

메모이제이션이 효과적인 상황
|
✅대용량 데이터 처리
|
1,000+ 건 필터링/정렬
|
100ms → 2ms
|
|
✅복잡한 객체 생성
|
{ user, permissions, config }
|
자식 리렌더 방지
|
|
✅비용 높은 계산
|
피보나치, deep clone
|
응답성 향상
|
|
❌단순 값 할당
|
const title = name + '님'
|
오버헤드 > 이득
|
반응형
'교육' 카테고리의 다른 글
| react-helmet의 기본 개념과 사용법 (0) | 2025.11.18 |
|---|---|
| 「React 18 + TypeScript + MobX 기반 구조에서 useStore 훅 설계와 스토어 계층 아키텍처 이해」 (0) | 2025.11.17 |
| "TypeScript 제네릭 기반 Form 재사용 패턴: React Hook Form과 함께하는 고급 Form 설계" (0) | 2025.11.17 |
| #006 Context Provider (컨텍스트 프로바이더) (0) | 2025.11.13 |
| #005 React Context 교육자료: 장바구니 상태 관리 (0) | 2025.11.12 |