본문으로 바로가기

과거에 state를 업데이트함에 있어 비동기적 속성을 언급한 적이 있습니다. 

state가 바뀌면 재 렌더되고, 재 렌더된 후에 state가 바뀐 것을 확인할 수 있다는 내용이었습니다.

https://darrengwon.tistory.com/651

 

복잡해지니 단순히 state에 대해 정리하자면,

1. state가 바뀌면 해당 state를 사용하는 컴포넌트와 그 하위 자식 컴포넌트들은 재렌더링 된다.
 => 때문에 재렌더링을 최소화하기 위해 필요한 state에 따라 컴포넌트를 분리해야 한다
 => 대표적으로 삼항연산자, form, 반복문(map, filter...), redux에서 state를 받아 쓰는 부분 등
 
2. 재 렌더링 된 후에 state가 반영된 것을 확인할 수 있으므로 setState 직후 state를 확인할 수는 없다.

3. 객체 형태로 setState를 하면 오브젝트 컴포지션이 되어 덮어씌워져 원하는 동작을 하지 않을 수도 있다.
  => 함수형 업데이트가 필요한 이유이다.

 

 

여기서는 state를 바꾸는데 사용되는 setState의 작동방식에 대한 비동기성을 살펴보겠습니다.

 

함수형 컴포넌트에서 useState 훅을 사용하던 클래스형 컴포넌트에서 setState를 사용하던 state를 변화시키는 동작은 asynchronous, 비동기적입니다.

 

 

비동기적인 이유는 리액트가 여러번 setState를 만나게 되면 batching하여 state를 업데이트하기 때문입니다. 매번 호출 순서대로 바로 업데이트하지 않고 인자로 전달된 객체들을 하나로 합치는 작업을 합니다. 이런 과정은 '오브젝트 컴포지션' 이라고 합니다. 

 

코드로 풀면 아래와 같다는 군요

 

이러한 비동기적인 방법을 해결하기 위해서는 setState에 값을 그대로 전달하는 것이 아니라 함수를 전달하면 됩니다. 이를 '함수형 업데이트'라고 합니다.

 

객체와 같은 형태가 아니라 함수이기 때문에 따로 오브젝트 컴포지션을 하지 않고 호출된 순서대로 큐에 넣고 큐에 넣어진 대로 함수를 실행합니다.

 

 

또, 이러한 함수형 업데이트를 진행할 때 함수는 컴포넌트 외부에 분리하는 것이 추후 테스트에 좋습니다.

이후 jest를 이용한 테스트에 관련된 포스트를 작성할 때 한 번 짚고 넘어가야 겠습니다.

 

// 비분리

function App() {
  const [counter, setcounter] = useState(0);

  const onClick = () => {
    return setcounter((prev) => prev + 1);
  };

  return (
    <div>
      <div>count : {counter}</div>
      <button onClick={onClick}>plus 1</button>
    </div>
  );
}

export default App;

 

// 분리. onClick 이벤트를 핸들링하는 함수 로직을 외부에 분리함.

function plusOne(prev) {
  return prev + 1;
}

function App() {
  const [counter, setcounter] = useState(0);

  const onClick = () => {
    return setcounter(plusOne);
  };

  return (
    <div>
      <div>count : {counter}</div>
      <button onClick={onClick}>plus 1</button>
    </div>
  );
}

export default App;

 

 

참고한 글)

 

 

setState 를 함수형으로 사용하기

리액트를 사용할 때 상태관리를 어떻게 해야할까? 그런데 상태 관리를 고민하기 이전에 무엇이 상태(state)고 어떤 것이 프로퍼티(props)가 되어야하는 것일까? 그리고 setState 어떻게 동작하는 것일

medium.com

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체