리액트 상태 업데이트는 왜 여러 번 해도 한 번만 적용될까?

김현준·2025년 7월 17일

리액트

목록 보기
11/11

리액트를 공부하다 보면 이런 코드를 한 번쯤은 써보게 된다

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

function handleClick() {
  setCount(count + 1);
  setCount(count + 1);
  setCount(count + 1);
}

"3번 증가시키려고 했는데... 결과는 1만 올라가네?"
이유가 뭘까?


상태 업데이트는 즉시 반영되지 않는다

리액트에서 setCount()즉시 상태를 바꾸지 않고,
"업데이트 예약"만 해두는 함수다.

그래서 위 코드를 실행하면, 아래처럼 실행됨

실행 시점count실행 결과
처음 렌더0setCount(0 + 1)1
두 번째0setCount(0 + 1)1
세 번째0setCount(0 + 1)1

→ 결국 setCount(1)이 3번 쌓이고, 마지막 하나만 적용됨
최종 count = 1


왜 이렇게 작동할까? – 일괄 처리(batch update) 때문!

리액트는 성능 최적화를 위해,
하나의 이벤트 안에서 발생한 여러 개의 setState 호출을 한 번에 처리한다.

이걸 "배치 처리(Batching)"라고 부른다.

리액트의 생각:

"어? 같은 이벤트 안에서 상태를 여러 번 바꾼다고?
렌더링은 한 번만 해도 되겠네!"


해결 방법: 함수형 업데이트 쓰기

setCount(count + 1) 대신
setCount(prev => prev + 1)를 쓰면 해결됨

function handleClick() {
  setCount(prev => prev + 1);
  setCount(prev => prev + 1);
  setCount(prev => prev + 1);
}

이제 리액트는 업데이트 함수 각각을 순서대로 적용해 준다:

단계prev 값결과
101
212
323

→ 최종 count = 3


전체 예제

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    // setCount(count + 1); // ❌ 결과: 1
    // 아래처럼 고치자
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
  }

  return (
    <>
      <h1>{count}</h1>
      <button onClick={handleClick}>+3</button>
    </>
  );
}

요약

패턴설명결과
setCount(count + 1)렌더 시점의 count만 참조 → 같은 값 3번 요청됨1
setCount(prev => prev + 1)이전 값을 기준으로 순서대로 업데이트3

기억할 것

  • 리액트는 이벤트 핸들러 안에서 발생한 여러 상태 변경을 모아서 한 번만 리렌더링함.
  • 상태를 누적해서 바꾸고 싶다면 반드시 prev => prev + 1처럼 함수형 업데이트를 사용하자.
  • 그 이유는 setState가 바로 상태를 바꾸는 게 아니라 예약만 하기 때문이다.

참고자료

profile
기록하자

0개의 댓글