[React]⚡️React 성능 최적화 정리: memo, useMemo, 그리고 key의 역할까지!

2025. 4. 17. 21:45·Programming/React
728x90
반응형

이 글은 Udemy의 【한글자막】 React 완벽 가이드 2025 with React Router & Redux 를 수강하고 정리한 내용입니다.

 

 

🎈 memo 함수

  • memo 함수는 불필요한컴포넌트를 다시 렌더링 하지 않도록 방지하는 함수입니다.
import React, { memo } from "react";

const MyComponent = memo(function MyComponent(props) {
  // ...
});
  • 부모 컴포넌트가 렌더링되면 자식 컴포넌트도 기본적으로 함께 렌더링됩니다. 하지만 자식 컴포넌트의 props가 변하지 않았다면 굳이 다시 렌더링할 필요가 없습니다.
  • 이럴 때 memo로 감싸면, props가 이전과 동일할 경우 렌더링을 건너뜁니다. 즉, 컴호넌트 함수가 다시 호출 되지 않게 됩니다.
  • ✅ 사용 전: 상태 변경 시 Counter 컴포넌트가 계속 실행됨

  • ✅ 사용 후: memo 적용 시 Counter는 props가 동일하면 재실행되지 않음

✅ 작동 원리

  • memo는 이전 props와 새로운 props를 얕게(shallow) 비교해서 동일하면 컴포넌트를 재실행하지 않도록 막습니다.
  • 함수 컴포넌트 내의 상태가 바뀌는 건 막지 않아요. 부모 컴포넌트로부터 호출되는 경우에만 최적화됩니다.

⚠️ 모든 컴포넌트에 memo를 쓰는 건 오히려 성능 저하를 불러올 수 있습니다.

  • props가 객체나 함수일 경우 비교가 까다로워 매번 새로 만들어졌다고 판단할 수 있기 때문입니다.
  • 그래서 렌더링이 자주 발생하지만 props는 거의 바뀌지 않는 컴포넌트에만 사용하는 게 좋습니다.

 

 


🎈 useMemo() 훅

  • useMemo()는 컴포넌트 내부의 복잡한 연산이 포함된 함수의 재실행을 방지하는 데 사용됩니다.
  • memo가 전체 컴포넌트의 리렌더링을 막는 것과 달리, useMemo는 특정 값의 계산 결과를 메모이제이션합니다.
const initialCountIsPrime = useMemo(
  () => isPrime(initialCount),
  [initialCount]
);
  • 첫 번째 인자는 실행할 함수를 전달하고, 두 번째 배열은 해당 함수를 다시 실행할 조건을 지정합니다.
  • 의존성 배열 내 값이 바뀌지 않는 한, 이전에 계산한 값을 재사용합니다.

⚠️ useMemo 또한 모든 연산에 무조건 사용하는 것은 좋지 않습니다.

메모이제이션을 위한 연산도 비용이 들기 때문에, 연산이 무겁고 자주 바뀌지 않는 값에만 사용하는 것이 좋습니다

 

 

 


🎈 컴포넌트 함수의 실행 흐름

  1. 컴포넌트가 실행되면, React는 가상 DOM(Virtual DOM) 을 생성합니다.
  2. 이 가상 DOM과 이전 렌더의 가상 DOM을 비교하여 변경 사항을 찾아냅니다.
  3. 변경된 부분만 실제 DOM에 적용하여 성능을 최적화합니다.

가상 DOM을 사용하는 이유는 실제 DOM 조작보다 훨씬 빠르게 메모리에서 연산이 가능하기 때문입니다.

 

 


🎈 State 관리에서 key의 역할

  • 컴포넌트는 각자 고유한 state를 가지며, 같은 컴포넌트를 여러 번 사용해도 상태는 서로 독립적입니다.
  • 배열을 렌더링할 때 key 값을 index로 사용하는 것은 지양해야 합니다.
  • 그 이유는 다음과 같습니다:

문제점:

  • 배열 앞에 요소가 추가되면 기존 index가 바뀌어, 잘못된 상태가 다른 항목에 적용될 수 있습니다.
  • React가 변경 여부를 정확하게 파악하지 못해 전체 항목을 다시 렌더링할 수 있습니다.

해결 방법:

  • key는 고유 ID를 사용하는 것이 바람직합니다.
  • 이렇게 하면 React가 각 항목을 정확히 추적할 수 있어 불필요한 렌더링을 줄이고 성능도 향상됩니다.

 

 

 


🎈 key의 또 다른 역할

<Counter initialCount={chosenCount} />
  • 위 코드에서 chosenCount가 변경되어도, Counter 컴포넌트는 재사용되며 내부 상태는 유지됩니다.
  • 이는 useState(initialCount)가 최초 렌더링 시 초기값만 사용하는 특성 때문입니다.
<Counter key={chosenCount} initialCount={chosenCount} />
  • 반면, key를 설정하면 React는 chosenCount가 바뀔 때 이전 컴포넌트를 언마운트하고 새로 마운트합니다.
  • 즉, 완전히 새로운 컴포넌트로 인식하게 됩니다.

참고: key는 props처럼 전달되지만, 자식 컴포넌트에서는 props.key로 접근할 수 없습니다.

이는 React 내부에서만 사용하는 식별자입니다.

 

 


🎈 상태 업데이트의 스케줄링 & 배칭

  • setState는 즉시 실행되지 않고, React가 업데이트 일정을 조정합니다 (비동기 처리).
  • 따라서 상태를 설정한 직후 console.log로 출력하면, 이전 값이 출력되는 경우가 많습니다.

안전한 상태 업데이트 방식:

setCount(prev => prev + 1);
  • 위와 같이 이전 상태를 기반으로 한 함수형 업데이트를 사용하면,
  • 상태 업데이트가 여러 번 연달아 일어나도 정확하게 처리됩니다.

배칭(Batching)

  • 여러 개의 상태 업데이트가 동시에 발생하면 React는 이를 하나의 렌더링으로 묶어 처리합니다.
  • 이렇게 하면 불필요한 렌더링을 줄이고 성능을 최적화할 수 있습니다.

 

 


🎈 Million.js로 React 성능 최적화

  • Million은 React 앱의 렌더링 성능을 향상시켜주는 경량 라이브러리입니다.
npm install million

// vite.config.js
import MillionLint from "million/compiler";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [MillionLint.vite({ auto: true }), react()],
});
  • 설정만으로 자동 성능 최적화를 적용할 수 있습니다.

 

 

 


🧠 마무리 정리

기능 목적 사용 시기

memo 불필요한 자식 렌더링 방지 props가 자주 바뀌지 않는 경우
useMemo() 복잡한 계산 결과 캐싱 무거운 연산이 있을 때
key 컴포넌트 구분 & 성능 최적화 리스트 렌더링, 상태 꼬임 방지
함수형 setState 상태 안정적 업데이트 여러 상태 업데이트가 동시에 일어날 때

 

 

도움이 되셨다면 ❤️ 좋아요와 댓글로 피드백 주세요!

궁금한 점이 있다면 언제든지 질문 환영입니다 😄

지금까지 읽어주셔서 감사합니다!

반응형

'Programming > React' 카테고리의 다른 글

[React] HTTP 통신 : fetch로 데이터 요청하고 로딩/에러 처리까지  (0) 2025.04.22
[React] 리액트 클래스 컴포넌트, 왜 아직도 알아야 할까?  (1) 2025.04.18
[React] React로 퀴즈 앱 만들기 | 개발 회고  (1) 2025.04.16
[React] Side Effects / useEffect 훅 / useCallback 훅  (0) 2025.04.11
[React] Prop Drilling / Context API / Provider Pattern / userReducer  (0) 2025.04.09
'Programming/React' 카테고리의 다른 글
  • [React] HTTP 통신 : fetch로 데이터 요청하고 로딩/에러 처리까지
  • [React] 리액트 클래스 컴포넌트, 왜 아직도 알아야 할까?
  • [React] React로 퀴즈 앱 만들기 | 개발 회고
  • [React] Side Effects / useEffect 훅 / useCallback 훅
제가안난데여♪(´ε`*)
제가안난데여♪(´ε`*)
기억의 유한함을 기록의 무한함으로 ✍️ 예비 개발자가 꿈꾸는 공간 여기는 안나의 개발 블로그 💻
  • 제가안난데여♪(´ε`*)
    안나의 전두엽 어딘가 🧠
    제가안난데여♪(´ε`*)
    기억의 유한함을 기록의 무한함으로 ✍️ 예비 개발자가 꿈꾸는 공간 여기는 안나의 개발 블로그 💻
  • 전체
    오늘
    어제
    • 분류 전체보기 (128)
      • 간단하게 한스푼🥄 (1)
      • Programming (56)
        • Spring (16)
        • Vue.js (6)
        • Deep Learning (3)
        • DataBase (5)
        • React (26)
      • DevOps (21)
        • Docker (12)
        • Linux (4)
      • Algorithm (46)
        • 알고리즘 정리 (5)
        • 자료구조 (0)
        • PS - 백준 (28)
        • 99클럽 코테 스터디 (13)
      • Project (0)
        • CampFire (0)
      • 안나의 취뽀일기 (˵ •̀ ᴗ - ˵ ) ✧ (4)
        • SSAFY_9기 (2)
        • SW 부트캠프 (2)
  • 잔디 달력

    «   2026/01   »
    일 월 화 수 목 금 토
    1 2 3
    4 5 6 7 8 9 10
    11 12 13 14 15 16 17
    18 19 20 21 22 23 24
    25 26 27 28 29 30 31
  • 인기 글

  • 태그

    항해99
    Vue
    도커컨테이너
    linux
    김영한
    topology sort
    java stack
    til
    Vue.js
    백준 java
    java 백준
    백준
    알고리즘
    stack
    백준 구현문제
    개발자 취업
    자바 스택
    도커
    99클럽
    React
    greedy
    자바
    front-end
    java
    docker
    Spring
    코딩테스트 준비
    리액트 상태
    Vue.js 입문하기
    springboot
  • 01-25 01:49
    반응형
  • hELLO· Designed By정상우.v4.10.3
제가안난데여♪(´ε`*)
[React]⚡️React 성능 최적화 정리: memo, useMemo, 그리고 key의 역할까지!
상단으로

티스토리툴바