setState 동작 방식

dia·2022년 11월 23일
0

리액트 기초

목록 보기
4/5
post-thumbnail

콘솔에 state 값을 찍을때마다 예상했던 값이 안 나와서 당황했던 적이 많다.
분명 counter+1 하는 버튼 3번 눌렀으면 값이 3이 나와야되는데 2가 나온다. 왜일까?

setState의 비동기 동작

이는 setState가 비동기적으로 동작하기 때문이다.

공식문서에서는 setState가 state의 업데이트를 '스케쥴링'한다고 설명한다. 즉, 즉시 데이터가 업데이트 되는 것이 아니라 일종의 업데이트 예약을 하는 것이다(비동기적).

const [counter, setCounter] = useState(0);

const clickHandler = () => {
  setCounter(counter+1);
  console.log(counter);
}

return (
  <>
    <p>{counter}</p>
  	<button onClick={clickHandler}>Increase</button>
  </>
)

counter의 초기값이 0이고 counter+1 하는 버튼을 한번 눌렀을때 화면에는 업데이트된 값이 잘 뜨지만 콘솔창에 기대했던 값 1이 아니고 0이 뜨는 이유는 setCounter()가 비동기로 동작하여 console.log()가 먼저 실행되었기 때문이다. 좀더 쉬운 이해를 위해 동작순서를 차례로 적어보았다.

  1. button 클릭
  2. clickHandler 함수 호출 및 실행
  3. setCounter() 함수 실행 but, 비동기라 보류되고(=아직 counter+1 되지 않음) 바로 다음 코드 실행
  4. console.log()로 counter를 콘솔에 찍는다. 아직 counter+1 되지 않았으므로 초기값인 0이 찍힌다.
  5. 이벤트 루프에 의해 setCounter(counter+1)가 실행되고 state 값이 업데이트됨에 따라 리렌더링
  6. 화면에 업데이트된 값(1)이 렌더된다.

왜 비동기로 동작할까?

불필요한 리렌더링을 막아 효율적인 성능을 기대하기 위해서이다.
컴포넌트 내의 다수의 state가 있는 경우 그만큼 state 업데이트 횟수도 많아지고 그때마다 매번 리렌더링을 하게 되어 성능 저하의 문제가 생길 수 있다.
리액트는 컴포넌트의 이벤트 핸들러 내의 모든 setState 호출을 기다렸다가 리렌더링 전에 한꺼번에 처리한다. 즉, 변경되는 state들을 한꺼번에 모아 한번에 업데이트 시킴으로서 불필요한 리렌더링을 줄이는 것이다.

profile
얼레벌레 프론트엔드 개발자

0개의 댓글