setState를 바르게 사용하는 방법

setState는 비동기로 동작합니다.
따라서 다음과 같은 코드를 실행하면

state = { count: 0 }

this.setState( { count: this.state.count + 1 } );
this.setState( { count: this.state.count + 1 } );
this.setState( { count: this.state.count + 1 } );

count에 남는 값은 1입니다.
따라서 콜백을 이용하거나 동기로 처리할 수 있도록 함수를 래핑해야 한다는 것이 기존에 알려진 내용입니다. 그런데… 최근 문서가 업데이트가 되었습니다.

https://reactjs.org/docs/react-component.html#setstate

기존에 알고 있던 오브젝트를 이용하는 방법은 뒤로 가 있고, updater 라고 명명된 함수를 전달하는 방법이 더 먼저 제시됩니다.

setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.

setState() 는 구성 요소 상태의 변경 사항을 대기열에 넣고 React에 이 구성 요소와 그 하위 요소를 업데이트 된 상태로 다시 렌더링해야한다고 알립니다.

함수 형태로 전달되는 업데이터에는 그 순번의 대기열이 실행되는 시점의 state가 참조로 제공되므로, 다음과 같이 코드를 작성할 수 있습니다.

state = { count: 0 }

this.setState( state => ( { count: state.count + 1 } ) );
this.setState( state => ( { count: state.count + 1 } ) );
this.setState( state => ( { count: state.count + 1 } ) );

최종적으로 state의 count는 3이 됩니다.

immer 를 사용한다면 다음과 같이 작성할 수 있을겁니다.

import produce from 'immer';

state = { count: 0 }

this.setState( state => (
  produce( state, draft => { draft.count = state.count + 1 } )
) );
this.setState( state => (
  produce( state, draft => { draft.count = state.count + 1 } )
) );
this.setState( state => (
  produce( state, draft => { draft.count = state.count + 1 } )
) );

이제 setState에 객체를 바로 전달하지 말고, 업데이터 함수를 통해서 전달하도록 하는 것이 좋겠습니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다