React | 클래스형 컴포넌트의 setState의 비동기

dev_hee·2022년 2월 11일
1

React

목록 보기
2/7
post-thumbnail

setState는 비동기적으로 동작한다.

리액트의 클래스형 컴포넌트에서 상태 값을 업데이트할 때 사용되는 메서드인 setState는 비동기적으로 동작합니다.

비동기적으로 setState가 동작한다는 의미가 어떤 의미인지 다음 Counter 예제를 들며 설명해보겠습니다.

import React, { Component } from 'react';

class Counter extends Component {
  state = {
    number: 0,
    fixedNumber: 0,
  };
  render() {
    const { number } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <button
          onClick={() => {
            this.setState({ number: number + 1 });
            this.setState({ number: number + 1 });
            this.setState({ number: this.state.number + 1 });
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;
  • 버튼을 누르면 1씩 증가한다.

위의 클래스형 컴포넌트에서 button을 클릭하면, 상태 number의 값이 3씩 증가할 것 이라고 우리는 예측합니다. 하지만 실제로는 1씩 증가합니다. 그 이유는 setState비동기적으로 동작하기 때문입니다.

만약 부모와 자식이 click이벤트가 발생해서 모두 상태를 변경하는 setState를 호출했다고 합시다. 그러면 부모에서 상태가 변경되었고 자식에서도 상태가 변경되었으니, 상태가 총 2번 변경 되었습니다. 따라서 리액트는 해당 상태를 참조하여 렌더링하는 컴포넌트를 총 2번 렌더링해야합니다.

이는 리액트가 불필요한 렌더링이라고 판단하였습니다. 따라서 리액트는 브라우저 이벤트가 끝날 시점에 state를 일괄적으로 업데이트하여 한번만 렌더링하도록 성능을 개선시켰습니다.

즉, 리액트는 이벤트가 끝날 시점에 첫 번째, 두 번째, 세 번째 setState는 비동기적으로 호출되고 상태를 일괄적으로 업데이트 합니다.

상태 업데이트를 여러번 하고 싶다면?

setState가 비동기적으로 동작하여 위의 예제처럼 우리가 예상하는 대로 상태가 업데이트 되지 않았습니다. 그렇다면 number을 3 증가시키고 싶다면 어떻게 해야할까요?

다음과 같이 setState에게 인수로 함수를 넘겨주면 됩니다.

this.setState((prevState, props) => ({
	number: prevState.number + 1
}));

함수의 첫번재 인수인 prevState는 기존 상태이고, props는 현재 지니고 있는 props를 가리킵니다. 하나의 이벤트에서 호출된 핸들러안에서 여러번 setState를 호출하면, prevState를 통해서 바로 직전에 업데이트된 상태를 참조할 수 있습니다.

위의 예시를 아래처럼 수정하면 button을 클릭하였을 때 3씩 증가하는 것을 확인할 수 있습니다.

import React, { Component } from 'react';

class Counter extends Component {
  state = {
    number: 0,
    fixedNumber: 0,
  };
  render() {
    const { number } = this.state;

    return (
      <div>
        <h1>{number}</h1>
        <button
          onClick={() => {
            this.setState((prevState, props) => ({
              number: prevState.number + 1,
            }));
            this.setState((prevState, props) => ({
              number: prevState.number + 1,
            }));
            this.setState((prevState, props) => ({
              number: prevState.number + 1,
            }));
          }}
        >
          +1
        </button>
      </div>
    );
  }
}

export default Counter;
  • 버튼을 누르면 3씩 증가한다.

참조
리액트 공식문서

profile
🎨그림을 좋아하는 FE 개발자👩🏻‍💻

0개의 댓글