본문으로 건너뛰기
프론트엔드 기초집LESSON 23

성능 기초: memo, useMemo, useCallback을 써야 하는 경우

난이도초급
예상 시간35분
선수지식이전 강의

23강. 성능 기초: memo, useMemo, useCallback을 써야 하는 경우

1. 이번 강의에서 해결할 문제​

검색 입력 때 큰 랭킹 목록의 정렬이 반복되어 눈에 띄게 느려졌다고 가정합니다. 모든 코드에 메모이제이션을 추가하지 않고 병목을 확인한 곳만 개선해야 합니다.

2. 학습 목표​

  • 렌더링과 느린 렌더링을 구분한다.
  • memo, useMemo, useCallback의 역할을 비교한다.
  • 측정 전 최적화와 잘못된 의존성의 위험을 피한다.

3. 핵심 개념​

다시 렌더링되는 것 자체는 정상입니다. React DevTools Profiler와 실제 상호작용으로 비용을 확인한 뒤 최적화합니다.

  • memo: props가 같을 때 컴포넌트 렌더링을 건너뛸 수 있게 합니다.
  • useMemo: 의존성이 같을 때 계산 결과를 재사용합니다.
  • useCallback: 의존성이 같을 때 함수 참조를 재사용합니다.

공식 React 문서는 memo를 정확성 도구가 아닌 성능 최적화로만 사용하라고 안내합니다. React Compiler를 적용한 프로젝트는 값과 함수를 자동 메모이제이션해 수동 사용 필요가 줄 수 있으므로 React TypeScript 문서와 memo 문서를 현재 환경에 맞춰 확인하세요.

4. 단계별 코드 예시​

Profiler에서 정렬 비용이 확인됐고 GameList를 memo로 감쌌다는 전제의 예시입니다.

파일 경로: game-release-dashboard/src/pages/RankingsPage.tsx

import { useCallback, useMemo, useState } from 'react';
import { GameList } from '../components/GameList';
import type { Game } from '../types/game';

export function RankingsPage({ games }: { games: Game[] }) {
const [minimumScore, setMinimumScore] = useState(0);
const [favoriteIds, setFavoriteIds] = useState<string[]>([]);

const rankedGames = useMemo(
() =>
games
.filter((game) => game.score >= minimumScore)
.toSorted((a, b) => b.score - a.score),
[games, minimumScore],
);

const toggleFavorite = useCallback((id: string) => {
setFavoriteIds((current) =>
current.includes(id)
? current.filter((item) => item !== id)
: [...current, id],
);
}, []);

return (
<GameList
games={rankedGames}
favoriteIds={favoriteIds}
onFavorite={toggleFavorite}
/>
);
}

파일 경로: game-release-dashboard/src/components/GameList.tsx

import { memo } from 'react';

export const GameList = memo(function GameList(props: GameListProps) {
return <section>{props.games.length}개 게임</section>;
});

5. 코드가 동작하는 이유​

useMemo는 games나 minimumScore가 바뀔 때만 필터와 정렬을 다시 수행합니다. toSorted는 원본 배열을 바꾸지 않습니다. useCallback은 함수 prop의 참조를 유지해 memo의 props 비교가 불필요하게 깨지는 일을 줄입니다. 다른 props가 매번 새 객체라면 memo 효과는 사라집니다.

6. 자주 하는 실수와 해결법​

  • 성능 문제 없이 모두 감쌈: 코드 복잡도만 늘어납니다. Profiler로 먼저 측정합니다.
  • 의존성 누락: 오래된 값을 캡처할 수 있습니다. 린트 규칙을 따릅니다.
  • memo로 로직 버그를 숨김: 메모이제이션 없이도 올바르게 동작하도록 먼저 고칩니다.
  • 값싼 계산까지 useMemo: 메모 관리 비용과 가독성 손실이 더 클 수 있습니다.

7. 직접 실습​

React DevTools Profiler로 검색 전후 commit을 기록하세요. 게임 수를 충분히 늘려 실제 지연이 있을 때만 정렬에 useMemo를 적용하고 적용 전후 시간을 메모하세요.

8. 이해 점검 질문 3개​

  1. memo, useMemo, useCallback은 각각 무엇을 재사용하나요?
  2. useCallback이 memo 없이 항상 성능을 높이지 않는 이유는 무엇인가요?
  3. React Compiler를 사용하는 환경에서 수동 메모이제이션 판단이 달라질 수 있는 이유는 무엇인가요?

9. 핵심 요약​

성능 최적화는 측정에서 시작합니다. 병목이 확인된 렌더링, 계산, 함수 참조에만 알맞은 도구를 적용하고 정확성은 메모이제이션에 의존하지 않습니다.

MINI QUIZ

성능 기초: memo, useMemo, useCallback을 써야 하는 경우 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“성능 기초: memo, useMemo, useCallback을 써야 하는 경우” 실습 결과를 해석하는 올바른 기준은 무엇인가요?
  2. 문제 2‘의존성 누락’ 상태에 관한 “성능 기초: memo, useMemo, useCallback을 써야 하는 경우” 본문의 설명으로 가장 알맞은 것은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

23강. 성능 기초: memo, useMemo, useCallback을 써야 하는 경우 미완료 상태