useState는 동기 비동기? (동기적 처리)

민순기·2022년 2월 18일
29
post-thumbnail

며칠전 기술 면접을 보러가서 useState는 동기일까요 비동기일까요? 비동기라면 동기적 처리를 하기 위해서는 어떤 방법을 써야 할까요? 라는 질문을 받았다.

이 질문을 받기 전까지는 그냥 상태 관리하는 훅이고, 구조분해할당 방식으로 선언하고, setState하면 상태가 변하고 그냥 이런 정도만 알고 있었고 더 알고자 하는 생각도 없었다.

그런데 이 질문을 받고 나니 내가 너무 안일했다는 생각이 들었고 결과적으로 useState는 동기인가 비동기인가 (비동기이다) 그럼 동기적인 처리를 하기 위해서는 어떻게 해야 하는가? 에 대해서 포스팅하게 되었다.


useState의 비동기적 동작

useState는 동기인가 비동기인가에 대한 결론부터 얘기하자면 비동기로 동작한다.
( 정확하게 얘기하면 setState가 비동기로 동작한다. )

아래의 예시를 보자.

실행하기 전에 예측을 해보면 버튼을 클릭할 때마다 setNumbers(numbers + 1)을 세 번 해줌으로써 numbers를 3씩 증가시킬것 같다.

하지만 결과를 보면 버튼을 클릭할 때마다 3이 아니라 1씩 증가하는 것을 확인할 수 있다.

그럼 setState는 비동기로 동작할까?

이유

하나의 페이지나 컴포넌트 내에도 수많은 상태값이 존재한다. 만약 이 상태 하나하나가 바뀔 때마다 화면을 리렌더링 한다면 문제가 생길수도 있다.

때문에 리액트는 성능의 향상을 위해서 setState를 연속 호출하면 배치 처리하여 한 번에 렌더링하도록 하였다. 아무리 많은 setState가 연속적으로 사용되었어도 배치 처리에 의해서 한 번의 렌더링으로 최신 상태를 유지하는 것이다.

배치란? (batch)

배치란 React가 너 나은 성능을 위해 여러개의 state 업데이트를 하나의 리렌더링으로 묶는 것을 의미한다.
React는 16ms 동안 변경된 상태 값들을 하나로 묶는다. (16ms 단위로 배치를 진행한다.)

useState in React module

이제 useState가 왜 비동기로 동작하는지 알았다. 하지만 뭔가 조금 아쉬워서 React의 코드를 뜯어보았다.

React의 useState 함수이다. 이 함수는 resolveDispatcher라는 함수가 반환하는 객체의 useState라는 메서드를 실행하여 반환되는 값을 리턴한다.

그럼 이제 resolveDispatcher를 살펴보자.

resolveDispatcher 함수는 다시 ReactCurrentDispathcer라는 객체의 current 속성을 반환한다.

useStateReactCurrentDispatcher 객체의 useState 메서드를 실행시키는 것이다.
이때 주목할 점은 ReactCurrentDispatcher가 객체라는 점이다.

객체이기 때문에 동일한 key 값에 대하여 이전의 값을 계속해서 덮어쓴다. 결국에는 마지막 명령어만 수행되는 셈이다. 아래처럼.


출처 https://garve32.tistory.com/m/39

그럼 useState를 동기적으로 처리하려면?

useState를 동기적으로 처리하는 방법은 지금 생각나는 것은 2가지가 있다.

첫 번째로는, useEffeect의 의존성 배열을 이용하는 것이다.
두 번째로는, setState의 인자로 함수를 집어넣는 것이다.

( 면접관님이 useEffect의 의존성을 이용해 동기적 처리를 할 수 있다고 친절하게 말씀해주셨지만 아직 어떻게 의존성으로 동기적 처리를 하는지는 잘 모르겠다...ㅠ 의존성으로 하니까 무한루프 돌던데...)

이렇게 setState의 인자로 함수를 집어넣으면 동기적으로 동작하는 것을 확인할 수 있다.
( setState내 함수의 매개변수로 이전 상태가 들어온다. )


결론

  • useState는 비동기적으로 동작하는 훅이다.
  • 비동기적으로 동작하는 이유는 성능 최적화 때문이다.
  • 리액트는 성능을 최적화하기 위해 setState를 배치 처리한다.
  • useState를 동기적으로 처리하려면 인자로 함수를 집어넣거나 useEffect의 의존성 배열을 활용하면 된다.
profile
2년차 FE 개발자 민순기입니다.

4개의 댓글

comment-user-thumbnail
2023년 6월 6일

안녕하세요. 글 잘 보았는데 궁금한 게 있어서요.

useState는 ReactCurrentDispatcher 객체의 useState 메서드를 실행시키는 것이라고 했는데
글을 보면 아무리 봐도 useState 메서드가 안 보이는데 이 부분이 이해가 안 갑니다.

React의 useState 함수이다. 이 함수는 resolveDispatcher라는 함수가 반환하는 객체의 useState라는 메서드를 실행하여 반환되는 값을 리턴한다.

이 부분에 있는 사진을 아무리 봐도 useState라는 메서드를 실행한다고 했는데 사진에 usestate 매서드가 안 보입니다. 혹시 이 댓글 보시면 좀 도와주세요 부탁드리겠습니다.

2개의 답글
comment-user-thumbnail
4일 전

글 잘 읽고 갑니다.
왜 dispatcher === null 가 아닌 !(dispatcher !== null) 인 것인가가 신경쓰이네요.

답글 달기