[React] setState는 왜 비동기일까?

YJ·2023년 7월 26일
0

Q. React에서 상태값이 변경될 때마다 렌더링이 일어나는가?

처음 이 질문을 보자마자 들었던 생각은 '당연한거 아냐?' 였다.
State가 변경되면 React는 이를 감지해 리렌더링이 발생하고, 갱신된 state로 UI를 새로 그렸기 때문이다.
그러나 확신은 없었다. 이렇게 간단한 문제였으면 묻지도 않았을테니...


☝🏼 우선, 위의 질문에 답하기 위해서는 React 내부 동작 원리와 상태값 변경, 렌더링의 원리를 이해하고 있어야 할 것이다.

setState 역할

공식 문서를 보면, "setState()는 컴포넌트 state의 변경 사항을 대기열에 집어넣고, React에게 해당 컴포넌트와 그 자식들이 갱신된 state를 사용하여 다시 렌더링되어야 한다고 알립니다. 이 메서드는 이벤트 핸들러와 서버 응답 등에 따라 UI를 갱신할 때에 가장 많이 사용하는 메서드입니다." 라고 돼있다.

즉, setState()가 쓰일 때, 컴포넌트의 state 객체에 대한 업데이트를 실행한다. state가 변경되면 컴포넌트는 리렌더링 된다.

그렇다면 언제 setState가 비동기로 작동할까?

import React, { useState } from "react";

function App() {
  const [state, setState] = useState(1);

  const onClick = () => {
    setState(state + 1);
    console.log(state);
  };

  return (
    <div className="App">
      <button onClick={onClick}>+1</button>
      <p>현재 값 {state}</p>
    </div>
  );
}

export default App;

현재 setState는 이벤트 핸들러 내에서 비동기적이다.

위 코드는 state 값은 반영이 되지만, console에 찍힌 값은 이전 상태 값을 출력한다(console.log의 결과값이 이전 상태를 나타냄).

React가 브라우저 이벤트가 끝날 시점에 state를 일괄적으로 업데이트하기 때문인데, 왜 그렇게 하는걸까?

연속적으로 setState 호출 시 발생하는 문제점

import React, { useState } from "react";

function App() {
  const [state, setState] = useState(1);

  const onClick = () => {
    setState(state + 1);
    setState(state + 1);
    setState(state + 1);
  };

  return (
    <div className="App">
      <button onClick={onClick}>+1</button>
      <p>현재 값 {state}</p>
    </div>
  );
}

export default App;

위 코드에서 원하는 결과는 버튼을 클릭할 때마다 매번 +3 씩 출력되게 하는 것이다. 하지만 오직 +1 씩만 증가해서 출력되는 걸 볼 수 있다.

그 이유는 React가 batch update를 하기 때문이다.

setState()를 연속적으로 호출하면 Batch 처리를 한다.

setState() 함수가 호출되면 리액트는 바로 전달받은 state로 값을 바꾸는 것이 아닌 이전의 리액트 엘리먼트 트리와 전달받은 state가 적용된 엘리먼트 트리를 비교하는 작업을 거치고, 최종적으로 변경된 부분만 DOM에 적용한다.

연속적으로 호출 시 해결 방안

setState() 함수는 인자로 새로운 state 객체를 인자를 받을 수도 있지만, 이전 state 값을 기준으로 값을 계산해야 한다면, 객체 대신 updater 함수를 전달해야 한다.

updater 함수를 전달하면 updater 함수 안에서 이전 state 값에 접근할 수 있다.

setState 호출은 일괄적으로 처리되기 때문에 여러 업데이트 사항이 충돌 없이 차례대로 반영된다.

 const onClick = () => {
    setState((prevState) => prevState + 1);
    setState((prevState) => prevState + 1);
    setState((prevState) => prevState + 1);
  };

위 코드로 수정하면, +1이 아닌 +3씩 증가하는 것을 볼 수 있다.

🤔 왜 React는 상태 값을 비동기적으로 처리하게 만들었을까?

React의 setState가 비동기로 작동하는 이유는 렌더링 횟수를 줄여 더 빠르게 동작하게 하기 위함인 것을 알 수 있다.

🤔 React가 리렌더링 시, 즉시 state를 업데이트 한다면?

props와 state 사이의 일괄성을 해칠 수 있으며, 디버깅하기 힘든 이슈가 생길 수 있다.


※ 참고 자료
React 공식 문서
React - setState 이해하기
React - setState가 비동기인 이유

profile
Hello

1개의 댓글

comment-user-thumbnail
2023년 7월 26일

좋은 정보 얻어갑니다, 감사합니다.

답글 달기