본문으로 건너뛰기
프론트엔드 기초집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을 써야 하는 경우 미완료 상태