프론트엔드 개발

React - setState 이해하기 본문

Front-End/React

React - setState 이해하기

태나미 2021. 4. 10. 16:19
React에서 자주 사용되는 setState를 사용하는데 문제가 있었고,
어떠한 원리로, 비동기 동작을 하는지 이해하고 사용하려 한다.

setState 역할

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

state와 props의 차이점

props와 state는 Javascript 객체입니다. 두 객체 모두 렌더링 결과물에 영향을 주는 정보를 갖고 있습니다.

props는 컴포넌트에 전달되며, 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에 적용합니다. 

리액트는 batch update를 16ms 단위로 진행합니다.

16ms 동안 변경된 상태 값들을 모아서 단 한번 리렌더링을 진행합니다.

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

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

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

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

import React, { useState } from "react";

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

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

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

export default App;

위의 코드로 수정하면, +1씩  증가하는 게 아닌, +3 씩 증가하는 걸 볼 수 있습니다.

 

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

  • React의 setState 등이 비동기적으로 작동하는 이유는 일정 시간 동안 변화하는 상태를 모아 한 번에 랜더링 하기 위해서입니다.
  • 결국, 웹 페이지 불필요한 렌더링 횟수를 줄여 좀 더 빠른 속도로 동작하게 만들기 위해서입니다. 

왜 React는 리렌더링 대신 즉시 state를 업데이트하지 않는지?

  • props와 state 사이의 일괄성을 해칠 수 있으며 이것은 디버깅하기 힘든 이슈가 생길 수 있기 때문입니다.

 

 

출처: leehwarang.github.io/2020/07/28/setState.html

velog.io/@seongkyun/React%EC%9D%98-setState%EA%B0%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0

https://ko.reactjs.org/docs/faq-state.html

Comments