React 렌더링

Jinmin Kim·2025년 9월 25일

서론: 안정적인 서비스를 위한 React 렌더링 최적화의 중요성

React 애플리케이션의 성능과 안정성은 화면 뒤에서 일어나는 렌더링 메커니즘에 대한 깊은 이해에서 시작됩니다. 많은 개발자들이 React를 어느 정도 안다고 생각하지만, 막상 "컴포넌트는 정확히 언제, 어떻게 다시 그려지는가?" 라는 질문 앞에서는 자신 있게 답하기 어려워합니다.

  • useState의 상태 업데이트 동작
  • useMemo, useCallback 같은 메모이제이션 훅의 필요성
  • useEffect의 적절한 사용 시점

이 지식들은 예측 불가능한 버그를 막고, 사용자 경험을 극대화하는 핵심 열쇠입니다.

이 글에서는 React 렌더링의 기본 원리부터, 상태 관리의 핵심(useState), 자동 배칭(Automatic Batching), 그리고 최적화 훅(useMemo, useCallback, useEffect) 의 올바른 사용법까지 깊이 있게 다룹니다.


1. React 렌더링의 기본 원리: 언제, 어떻게 다시 그려지는가?

React 컴포넌트의 렌더링은 크게 두 가지입니다.

  1. 최초 렌더링 (Initial Render)
    컴포넌트가 처음 화면에 나타날 때, React는 코드를 순차적으로 실행하여 초기 UI를 구성합니다.

  2. 리렌더링 (Re-rendering)
    props나 state 값이 변경되면 컴포넌트를 다시 렌더링합니다. 이때 함수 전체가 다시 호출되며 내부 모든 코드가 다시 실행됩니다.

문제는 리렌더링이 불필요하게 자주 발생할 때입니다. 작은 상태 변화 하나가 많은 자식 컴포넌트를 연쇄적으로 리렌더링시켜 성능 저하를 일으킵니다.


2. 상태 관리의 핵심, useState 깊게 파고들기

useState는 React에서 가장 기본적인 훅이지만, 그 동작 원리를 잘못 이해하면 버그를 만들기 쉽습니다.

핵심은 스코프(Scope)스냅샷(Snapshot) 입니다.

const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(count + 1);
  setCount(count + 1);
  setCount(count + 1);
};

👉 결과: **카운트 값: 1, 렌더링 횟수: 1**

- `handleClick` 실행 시 `count`0으로 고정된 **스냅샷 값**
- 따라서 세 번의 `setCount`는 모두 `1`을 설정하려는 시도
- React는 이를 **중복 업데이트**로 묶어 한 번만 적용

### 해결: 함수형 업데이트(Functional Update)

```tsx
const handleClick = () => {
  setCount(prev => prev + 1);
  setCount(prev => prev + 1);
  setCount(prev => prev + 1);
};

👉 최종 count = 3


3. React 17+의 마법: 자동 배칭 (Automatic Batching)

자동 배칭은 React가 여러 개의 상태 업데이트를 한 번의 렌더링으로 묶는 최적화 기법입니다.

  • React 17부터 이벤트 핸들러 내 여러 setState 호출 → 자동으로 하나로 묶임
  • 불필요한 중간 렌더링 방지 → 효율성 극대화

앞선 예제에서 세 번 setCount 했지만 렌더링이 한 번만 일어난 이유가 바로 자동 배칭입니다.


4. 불필요한 연산을 막는 방패: useMemo와 useCallback

useMemo — 값을 기억하다

const result = useMemo(() => heavyCalculation(data), [data]);
  • 복잡한 연산의 결과값을 메모
  • deps 변경 전까지 재계산 방지
  • 비유: 똑똑한 계산기

useCallback — 함수를 기억하다

const handleClick = useCallback(() => doSomething(), [deps]);
  • 함수 인스턴스 자체를 메모
  • 자식 컴포넌트에 prop으로 전달 시 불필요한 리렌더링 방지
  • 비유: 특별한 레시피 카드
구분useMemouseCallback
목적값의 메모이제이션함수 메모이제이션
반환 값값(Value)함수(Function)
사용 예시복잡한 연산 결과값 캐싱자식에 함수 전달 최적화

5. 렌더링과 분리된 작업: useEffect의 올바른 이해

useEffect렌더링 이후 부수효과(Side Effect) 를 처리하는 훅입니다.

예: API 호출, DOM 조작, 구독, 타이머 등

useEffect(() => {
  const id = setInterval(() => console.log("tick"), 1000);
  return () => clearInterval(id); // cleanup
}, []);
  • 렌더링 완료 후 실행 (UI 표시 이후 → 비동기)
  • 렌더 과정 방해 X, 사용자 경험 보장
  • cleanup 함수 필수: 메모리 누수 방지

결론: 똑똑한 훅 사용으로 만드는 견고한 React 애플리케이션

정리하면:

  1. 리렌더링 조건: state/props 변경
  2. useState와 클로저: 함수형 업데이트로 최신 상태 보장
  3. 자동 배칭: 여러 업데이트를 한 번의 렌더링으로
  4. useMemo/useCallback: 값·함수 메모이제이션으로 최적화
  5. useEffect: 렌더링과 분리된 부수효과 처리

올바른 훅 사용법을 이해하면 React 애플리케이션의 성능과 안정성을 모두 잡을 수 있습니다.

profile
Let's do it developer

0개의 댓글