며칠전 기술 면접을 보러가서 useState
는 동기일까요 비동기일까요? 비동기라면 동기적 처리를 하기 위해서는 어떤 방법을 써야 할까요? 라는 질문을 받았다.
이 질문을 받기 전까지는 그냥 상태 관리하는 훅이고, 구조분해할당 방식으로 선언하고, setState하면 상태가 변하고 그냥 이런 정도만 알고 있었고 더 알고자 하는 생각도 없었다.
그런데 이 질문을 받고 나니 내가 너무 안일했다는 생각이 들었고 결과적으로 useState
는 동기인가 비동기인가 (비동기이다) 그럼 동기적인 처리를 하기 위해서는 어떻게 해야 하는가? 에 대해서 포스팅하게 되었다.
useState
는 동기인가 비동기인가에 대한 결론부터 얘기하자면 비동기로 동작한다.
( 정확하게 얘기하면 setState
가 비동기로 동작한다. )
아래의 예시를 보자.
실행하기 전에 예측을 해보면 버튼을 클릭할 때마다 setNumbers(numbers + 1)
을 세 번 해줌으로써 numbers
를 3씩 증가시킬것 같다.
하지만 결과를 보면 버튼을 클릭할 때마다 3이 아니라 1씩 증가하는 것을 확인할 수 있다.
그럼 왜 setState
는 비동기로 동작할까?
하나의 페이지나 컴포넌트 내에도 수많은 상태값이 존재한다. 만약 이 상태 하나하나가 바뀔 때마다 화면을 리렌더링 한다면 문제가 생길수도 있다.
때문에 리액트는 성능의 향상을 위해서 setState를 연속 호출하면 배치 처리하여 한 번에 렌더링하도록 하였다. 아무리 많은 setState가 연속적으로 사용되었어도 배치 처리에 의해서 한 번의 렌더링으로 최신 상태를 유지하는 것이다.
배치란 React가 너 나은 성능을 위해 여러개의 state 업데이트를 하나의 리렌더링으로 묶는 것을 의미한다.
React는 16ms 동안 변경된 상태 값들을 하나로 묶는다. (16ms 단위로 배치를 진행한다.)
이제 useState
가 왜 비동기로 동작하는지 알았다. 하지만 뭔가 조금 아쉬워서 React의 코드를 뜯어보았다.
React의 useState
함수이다. 이 함수는 resolveDispatcher
라는 함수가 반환하는 객체의 useState
라는 메서드를 실행하여 반환되는 값을 리턴한다.
그럼 이제 resolveDispatcher
를 살펴보자.
resolveDispatcher
함수는 다시 ReactCurrentDispathcer
라는 객체의 current
속성을 반환한다.
즉 useState
는 ReactCurrentDispatcher
객체의 useState
메서드를 실행시키는 것이다.
이때 주목할 점은 ReactCurrentDispatcher
가 객체라는 점이다.
객체이기 때문에 동일한 key 값에 대하여 이전의 값을 계속해서 덮어쓴다. 결국에는 마지막 명령어만 수행되는 셈이다. 아래처럼.
출처 https://garve32.tistory.com/m/39
useState
를 동기적으로 처리하는 방법은 지금 생각나는 것은 2가지가 있다.
첫 번째로는, useEffeect
의 의존성 배열을 이용하는 것이다.
두 번째로는, setState
의 인자로 함수를 집어넣는 것이다.
( 면접관님이 useEffect
의 의존성을 이용해 동기적 처리를 할 수 있다고 친절하게 말씀해주셨지만 아직 어떻게 의존성으로 동기적 처리를 하는지는 잘 모르겠다...ㅠ 의존성으로 하니까 무한루프 돌던데...)
이렇게 setState
의 인자로 함수를 집어넣으면 동기적으로 동작하는 것을 확인할 수 있다.
( setState
내 함수의 매개변수로 이전 상태가 들어온다. )
useState
는 비동기적으로 동작하는 훅이다.- 비동기적으로 동작하는 이유는 성능 최적화 때문이다.
- 리액트는 성능을 최적화하기 위해
setState
를 배치 처리한다.useState
를 동기적으로 처리하려면 인자로 함수를 집어넣거나 useEffect의 의존성 배열을 활용하면 된다.
안녕하세요. 글 잘 보았는데 궁금한 게 있어서요.
useState는 ReactCurrentDispatcher 객체의 useState 메서드를 실행시키는 것이라고 했는데
글을 보면 아무리 봐도 useState 메서드가 안 보이는데 이 부분이 이해가 안 갑니다.
React의 useState 함수이다. 이 함수는 resolveDispatcher라는 함수가 반환하는 객체의 useState라는 메서드를 실행하여 반환되는 값을 리턴한다.
이 부분에 있는 사진을 아무리 봐도 useState라는 메서드를 실행한다고 했는데 사진에 usestate 매서드가 안 보입니다. 혹시 이 댓글 보시면 좀 도와주세요 부탁드리겠습니다.