누구나 로고
Online CoursesFor BusinessLibraryTrend InsightsFree coursesNoticesContactCareers
모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.
로그인무료 회원가입
강좌리액트 입문 — 컴포넌트로 만드는 웹18강

18강 / 전체 28강

useReducer

5분 읽기 조회 1

useMemo와 useCallback으로 불필요한 재계산·재생성을 방지하고, React.memo로 컴포넌트 리렌더링을 최적화하는 방법과 올바른 사용 기준을 배웁니다.

⚡ 성능 최적화는 꼭 필요할 때만

중요한 경고부터: useMemo, useCallback, React.memo는 남용하면 오히려 코드가 복잡해지고 성능이 나빠질 수 있습니다. 리액트는 기본적으로 충분히 빠릅니다. 이 훅들은 측정된 성능 문제가 있을 때만 적용하세요. 먼저 동작하게 만들고, 그다음 측정하고, 느리면 최적화합니다.

📦 useMemo — 비싼 계산 결과 캐싱

useMemo는 연산 결과를 메모이제이션(memoization)합니다. 의존성이 바뀌지 않으면 이전 계산 결과를 재사용합니다.

function ProductTable({ products, sortBy, filterText }: {
  products: Product[]
  sortBy: 'name' | 'price'
  filterText: string
}) {
  // filterText나 sortBy가 바뀔 때만 재계산
  const processedProducts = useMemo(() => {
    console.log('무거운 계산 실행됨')  // 이 로그가 매 렌더마다 찍히면 문제
    return products
      .filter((p) => p.name.includes(filterText))
      .sort((a, b) =>
        sortBy === 'price' ? a.price - b.price : a.name.localeCompare(b.name)
      )
  }, [products, sortBy, filterText])

  return (
    <table>
      <tbody>
        {processedProducts.map((p) => (
          <tr key={p.id}>
            <td>{p.name}</td>
            <td>{p.price.toLocaleString()}</td>
          </tr>
        ))}
      </tbody>
    </table>
  )
}

products가 1만 개 이상이거나 계산이 복잡할 때 효과적입니다. 단순한 필터링/정렬은 useMemo 없어도 충분히 빠릅니다.

🔄 useCallback — 함수 재생성 방지

컴포넌트가 렌더링될 때마다 내부에서 선언한 함수는 새로 생성됩니다. useCallback은 함수 자체를 메모이제이션합니다:

function Parent() {
  const [count, setCount] = useState(0)
  const [text, setText] = useState('')

  // ❌ 매 렌더마다 새 함수 생성 → ChildComponent가 불필요하게 리렌더
  const handleSomething = () => console.log('처리')

  // ✅ useCallback으로 함수 메모이제이션
  const handleSomethingMemo = useCallback(() => {
    console.log('처리')
  }, [])  // 의존성이 없으면 최초 한 번만 생성

  return (
    <div>
      <button onClick={() => setCount((c) => c + 1)}>{count}</button>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      {/* ChildComponent는 handleSomethingMemo가 바뀔 때만 리렌더 */}
      <ChildComponent onAction={handleSomethingMemo} />
    </div>
  )
}

useCallback이 효과를 내려면 받는 쪽 컴포넌트가 React.memo로 감싸져 있어야 합니다. 그렇지 않으면 useCallback은 의미가 없습니다.

🧱 React.memo — 컴포넌트 메모이제이션

React.memo로 감싼 컴포넌트는 Props가 바뀌지 않으면 리렌더링하지 않습니다:

// React.memo로 감싸기
const ExpensiveItem = React.memo(function ExpensiveItem({
  name,
  price,
  onDelete,
}: {
  name: string
  price: number
  onDelete: (name: string) => void
}) {
  console.log(`${name} 렌더링`)  // memo 없으면 부모 리렌더마다 출력됨

  return (
    <div className="flex justify-between p-3 border-b">
      <span>{name} — {price.toLocaleString()}원</span>
      <button onClick={() => onDelete(name)}>삭제</button>
    </div>
  )
})

🔬 최적화 결정 체크리스트

  • React.DevTools Profiler로 실제로 느린 컴포넌트를 확인했는가?
  • 계산이 진짜 무겁거나(수천 개 이상의 데이터 처리), 함수가 자주 재생성되어 자식 리렌더를 일으키는가?
  • 최적화 후 실제로 빨라졌는가?

이 세 질문에 모두 "예"라면 적용합니다. 그렇지 않으면 코드를 단순하게 유지하세요.

✅ 정리

  • useMemo: 비싼 계산 결과를 캐싱. 의존성이 바뀔 때만 재계산.
  • useCallback: 함수를 메모이제이션. React.memo와 함께 써야 효과적.
  • React.memo: Props가 같으면 리렌더링 방지.
  • 측정 없는 최적화는 시기상조. 먼저 동작하게 만들고, 느리면 그때 최적화하세요.

관련 주제

  • reducer 개념
  • action dispatch
  • useState 대비 장점
  • 복잡한 상태 관리 시나리오
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 리액트 입문 — 컴포넌트로 만드는 웹
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나
이전 17강Context API다음 19강 리스트 앱 실전 ①

댓글

0/1000

불러오는 중...

목차

  1. 1.리액트란 무엇인가
  2. 2.개발 환경 만들기 — Vite
  3. 3.JSX 기초
  4. 4.컴포넌트 만들기
  5. 5.Props로 데이터 전달
  6. 6.State와 useState
  7. 7.이벤트 처리
  8. 8.조건부 렌더링
  9. 9.리스트 렌더링과 key
  10. 10.폼 다루기
  11. 11.useEffect 기초
  12. 12.데이터 가져오기(fetch)
  13. 13.상태 끌어올리기
  14. 14.컴포넌트 합성과 재사용
  15. 15.useRef와 DOM 접근
  16. 16.커스텀 훅 만들기
  17. 17.Context API
  18. 18.useReducer
  19. 19.리스트 앱 실전 ①
  20. 20.리스트 앱 실전 ②
  21. 21.라우팅 — React Router
  22. 22.스타일링 방법들
  23. 23.리스트·상세 페이지 연결
  24. 24.비동기 상태 관리 패턴
  25. 25.성능 기초 — memo
  26. 26.에러 처리와 경계
  27. 27.환경변수와 빌드
  28. 28.배포하기

Support

  • Notices
  • FAQ
  • Contact Us
  • Community

Help & Info

  • Terms of Service
  • Privacy Policy
  • Refund Policy

Services

  • About Us
  • Sign up
  • New courses
  • Free courses
누구나 로고
Terms of ServicePrivacy PolicyRefund Policy

상호명: NUGUNA  |  대표자: 정우진  |  사업자등록번호: 392-32-01817  |  통신판매업신고: 제 2026-서울양천-0564 호

주소: 서울특별시 양천구 목동서로 100  |  이메일: nugunapass@gmail.com  |  전화: 010-6395-3043

© 2026 NUGUNA. All rights reserved.

KB예금주인증관리자
HomeCoursesLibraryContactMY