react-native

React Native 성능 최적화 기초: 리렌더링과 useMemo, useCallback 정리

mirabo01 2026. 1. 23. 09:59

상태 관리까지 정리했다면
이제 앱은 “기능적으로는” 꽤 그럴듯해진다.

그다음에 체감되는 문제가 하나 있다.

  • 화면 전환이 묘하게 버벅인다
  • 입력할 때 전체 화면이 다시 그려지는 느낌
  • 리스트가 많아지면 확 느려진다

이건 대부분
렌더링 구조를 제대로 이해하지 못한 상태에서
컴포넌트가 불필요하게 다시 그려지기 때문이다.

이 글에서는
React Native에서 성능 최적화를 시작할 때
가장 먼저 이해해야 할 포인트를 정리한다.


이 글이 필요한 사람

  • 앱이 커질수록 점점 느려지는 느낌이 드는 경우
  • useMemo, useCallback을 왜 쓰는지 감이 안 오는 경우
  • “일단 다 감싸면 되지 않나?”라고 생각한 적 있는 경우

React Native 성능의 핵심은 렌더링이다

React Native 앱에서
성능 이슈의 대부분은 이 한 문장으로 정리된다.

“필요 없는 리렌더링이 너무 많다”

React는 기본적으로
state나 props가 바뀌면
해당 컴포넌트를 다시 렌더링한다.

문제는
안 바뀌어도 되는 것까지 같이 렌더링되는 경우다.


리렌더링은 왜 문제가 될까

리렌더링 자체가 나쁜 건 아니다.
하지만 이런 상황에서는 문제가 된다.

  • 리스트 아이템이 수십 개 이상
  • 각 아이템에 이미지, 계산 로직 포함
  • 입력할 때마다 전체 리스트가 다시 렌더링됨

특히 모바일에서는
이게 바로 버벅임으로 체감된다.

[이미지: React Native 리렌더링 흐름 개념도]


먼저 체크해야 할 기본 원칙

useMemo, useCallback을 쓰기 전에
이 원칙부터 점검하는 게 맞다.

1️⃣ 컴포넌트 분리

// ❌ 모든 걸 한 컴포넌트에서 처리
// ✅ 역할별로 컴포넌트 분리
  • 화면 컴포넌트
  • 리스트 아이템 컴포넌트
  • 버튼 컴포넌트

성능 최적화의 절반은
컴포넌트 분리로 해결된다.


2️⃣ state 위치 점검

state가 너무 위에 있으면
불필요한 리렌더링 범위가 커진다.

  • 정말 전역 상태인가?
  • 이 화면에서만 써도 되는 상태 아닌가?

이걸 먼저 정리하지 않으면
hook으로 감싸도 근본 해결이 안 된다.


useMemo란 무엇인가

useMemo는
계산 결과를 기억해두는 hook이다.

const value = useMemo(() => {
  return expensiveCalculation(data);
}, [data]);
  • data가 바뀌지 않으면
  • 이전 계산 결과를 그대로 사용

useMemo를 언제 써야 할까

useMemo는
모든 곳에 쓰는 도구가 아니다.

다음 조건에 해당할 때 고려한다.

  • 계산 비용이 있는 로직
  • 렌더링마다 다시 계산할 필요 없는 값
  • 리스트 아이템 내부 계산

예시

const totalPrice = useMemo(() => {
  return items.reduce((sum, item) => sum + item.price, 0);
}, [items]);

단순한 값에는
useMemo를 쓰지 않는 게 오히려 낫다.


useCallback이 필요한 이유

React에서는
함수도 객체다.

즉, 렌더링될 때마다
함수가 새로 생성된다.

이게 왜 문제냐면
props로 함수를 넘길 때다.


useCallback 기본 개념

const handlePress = useCallback(() => {
  console.log('pressed');
}, []);
  • 의존성이 바뀌지 않으면
  • 같은 함수 참조를 유지

useCallback을 써야 하는 대표적인 경우

1️⃣ 자식 컴포넌트에 함수 전달

<Item onPress={handlePress} />

이때 Item이 memo로 감싸져 있다면
함수 참조가 바뀌는 순간
리렌더링이 발생한다.

2️⃣ FlatList renderItem 내부 함수

리스트 성능 최적화에서는
useCallback이 꽤 중요한 역할을 한다.


React.memo와 함께 생각해야 한다

useCallback은
혼자 쓰는 도구가 아니다.

보통은
React.memo와 함께 사용된다.

const Item = React.memo(({ onPress }) => {
  return <Pressable onPress={onPress} />;
});

이 조합이 있어야
**“진짜로 렌더링을 막는 효과”**가 난다.


흔한 오해들

❌ 모든 함수에 useCallback

→ 코드만 복잡해지고 효과 없음

❌ 모든 값에 useMemo

→ 오히려 성능 손해 가능

❌ 성능 문제 없는데 미리 최적화

→ 유지보수 난이도만 상승

성능 최적화는
문제가 보일 때 하는 게 맞다.


실무 기준으로 추천하는 접근 순서

  1. 컴포넌트 분리
  2. state 위치 재정리
  3. FlatList 구조 점검
  4. React.memo 적용
  5. 필요할 때 useMemo / useCallback

이 순서를 지키면
과한 최적화를 피할 수 있다.


정리

  • 성능 문제의 대부분은 리렌더링 때문이다
  • 컴포넌트 분리가 최우선이다
  • useMemo는 계산 최적화용이다
  • useCallback은 함수 참조 유지용이다
  • 문제를 확인한 뒤 적용하는 게 가장 좋다

다음 글에서는
FlatList 성능 최적화를 중심으로

  • keyExtractor
  • getItemLayout
  • windowSize
    같은 실무 옵션들을 정리해보려고 한다.