최적화 React Hook

김진효·2026년 8월 6일

[CS] 면접 대비

목록 보기
10/11
post-thumbnail

이전 기본 React Hook에 이어 이번에는 최적화의 관점에서 관련 Hook을 소개해보겠다!

React에서의 최적화

  • React App 내부의 최적화는 불필요한 작업 줄이는 것에 있음

    • 컴포넌트 내부의 불필요한 연산 방지
    • 컴포넌트 내부의 불필요한 함수 재생성 방지
    • 컴포넌트의 불필요한 리렌더링 방지

    React에서 리렌더링은 곧 성능(=렌더링 비용)과 직결

  • 리렌더링이 발생하는 상황

    1. 자신이 관리하는 state의 값이 변경될 때
      useState의 setter 함수로 상태를 변경하면 해당 컴포넌트 리렌더링
      (단, 이전과 동일한 값을 전달할 경우 변경이 없으므로 리렌더링도 발생하지 않음)
    2. 자신이 제공받는 props 의 값이 변경될 때
    3. 부모 컴포넌트가 리렌더링
      부모가 리렌더링되면 기본적으로 모든 자식 컴포넌트도 함께 리렌더링
    4. Context 값이 변경될 때
      useContext 로 구독 중인 Context의 값이 변경되면 해당 Context를 사용하는 컴포넌트가 리렌더링

useMemo

불필요한 연산 방지

계산 비용이 큰 연산 결과 값을 메모이제이션 기법으로 캐싱해, 의존성이 변경될 때만 재계산하여 불필요한 연산을 최적화

// 콜백함수, 의존성 배열
useMemo(()=>{},[])

// 예시
const memoizedValue = useMemo(() => {
  return computeExpensiveValue(a, b);
}, [a, b]);

렌더링 과정에서 의존성 배열에 포함된([a, b]) 값이 이전과 같은지 비교해서, 같으면 저장해둔 결과값을 즉시 반환하고, 다르면 콜백 함수를 다시 실행하여 계산


useCallback

불필요한 함수 재생성 방지

컴포넌트가 리렌더링 될 때마다 함수가 새롭게 정의되는 것을 방지하고, 이전에 만든 함수를 그대로 재사용

// 최적화하고 싶은 함수, 의존성 배열
useCallback(()=>{},[])

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

useMemo와 useCallback 차이

useMemo의 경우는 이 대상이고, useCallback함수가 대상

 useCallback(fn, deps)는 내부적으로 useMemo(() => fn, deps)와 동일하게 동작

React.memo

불필요한 리렌더링 방지

컴포넌트를 인수로 받아, props가 바뀌지 않으면 리렌더링을 건너뛰는 최적화된 컴포넌트를 반환

// 반환값: 최적화된 컴포넌트 = memo(컴포넌트)
const MemoizedComponent = memo(Component)

이 Memoized 컴포넌트는 부모 컴포넌트가 리렌더링 되더라도 자신이 받는 props가 바뀌지 않으면(얕은 비교 기준) 다시는 리렌더링이 발생하지 않도록 메모이제이션

두 번째 인수로 사용자 정의 비교 함수 전달 가능
React 가 스스로 props 변경 여부를 판단하는게 아니라,
이전 props와 다음 props를 함수에 넘겨주고 그 반환값으로 판단하도록

export default memo(TodoItem, (prevProps, nextProps)=>{
  
  // 반환값에 따라, Props가 바뀌었는지 안바뀌었는지 판단
  // true → props가 바뀌지 않음 → 리렌더링 X
  // false → props가 바뀜 → 리렌더링 o
  
  if (prevProps.id !== nextProps.id) return false
  if (prevProps.isDone !== nextProps.isDone) return false
  if (prevProps.content !== nextProps.content) return false
  if (prevProps.date !== nextProps.date) return false
  return true; // 여기까지 통과했다면 props가 동일한 것
})

🔎 최적화 언제 해야할까?

일단은 컴포넌트 구조를 먼저 고려해야한다

관련 없는 state 들을 하나의 컴포넌트에 두지 않고 서로 다른 컴포넌트로 분리하는 것만으로도 리렌더링을 방지할 수 있음

이후 성능 저하가 의심될 때 따져봐야 할 것

  1. 의존성 배열 비교에 따른 비용
  2. 메모리 사용량
  3. 코드 복잡도

useMemouseCallback 을 무분별하게 사용하면 위에 나열된 고려 사항으로 인해 더 비용이 들 수 있음
연산 혹은 처리량이 매우 많아서 렌더링의 문제가 되는 경우가 아니라면 단순한 연산이나 의도적인 값 변경에 굳이 쓰지 않는 편이 낫다
따라서, 기능 구현을 완성하고 난 뒤에 최적화가 필요한 지점을 실측으로 판단해본 뒤에 적용하는 것을 추천

// [참고] 자바스크립트의 실행 속도와 성능을 측정하는 도구
console.time() & console.timeEnd()
performance.now()
React Profiler

(➕) 추가

React 공식문서 내용을 보니 React Compiler가 빌드 타임에 컴포넌트를 정적 분석해서, 지금까지 손으로 작성하던 useMemo, useCallback, React.memo에 해당하는 메모이제이션을 자동으로 해주는 듯 하다
단, 컴파일러가 제어 흐름을 분석하기 어려운 코드 같은 경우는 예외일 수 있으니 컴파일러가 커버하지 못하는 예외 케이스에 집중하여 최적화가 필요한 여지는 남아있는 것으로 보인다

또한, 이 글에서 소개된 hook들은 없어도 코드가 정상 작동해야함을 유의하고 언제나 최적화 관점에서 다가가야 함을 유의하자



참고

Hooks의 종류
한 입 크기로 잘라 먹는 리액트
React의 useMemo와 useCallback을 과도하게 사용하면 안 되는 이유
내가 사용하는 useCallBack, useMemo가 진짜 성능 최적화를 진행중인걸까?
useMemo와 useCallback는 왜, 언제 사용할까?
React - useMemo
React - useCallback
React - memo

0개의 댓글