[React] 비동기적 setState
setState
는 함수형 컴포넌트 내에서 상태를 관리하게 위해 사용하는 useState
를 통해 반환되는 함수입니다.
기본적으로 setState
의 인자값에 변경하고자 하는 상태를 전달하여, 상태를 변경할 수 있습니다.
이 글에서는 setState
함수의 특징과 올바르게 사용하지 않았을 때 발생할 수 있는 오류에 대해서 알아보겠습니다.
setState의 특징
setState
함수는 다음 4가지 특징을 가지고 있습니다.
-
비동기적으로 동작한다.
-
연속적으로 호출하면 batch 처리를 한다.
-
setState
에state
객체 뿐 아니라, 새로운state
를 반환하는 함수를 인자로 넘겨줄 수 있다. -
state
는 객체이다.
다음으로 이러한 특징을 고려하지 않고 코딩할 때 발생할 수 있는 문제 예시에 대해서 살펴보겠습니다.
코드 예시
useState
를 사용해서 number의 상태를 변경시키는 예시입니다.
const [number, setNumber] = useState(1);
const add = () => setNumber(number + 1);
const subtract = () => setNumber(number - 1);
const multiplyBy2 = () => setNumber(number * 2);
const multiplyBy2AndAddBy1 = () => {
multiplyBy2();
add();
};
이 때 multiplyBy2AndAddBy1
함수를 실행시키면, multiplyBy2
후에 add
가 실행되는 것이 아니라, 의도한 바와 달리 add
만 실행이 됩니다.
이런 현상이 일어나는 이유는 무엇일까요?
문제의 원인
react
에서 여러 setState
호출을 만나면, 각 setState
에 전달된 객체를 모두 추출한 후 merge하여 단일 객체로 만듭니다.
이후 단일 객체를 사용하여 setState
를 수행합니다.
다음 예시코드를 통해 객체가 어떻게 merge되는지 살펴보겠습니다.
const singleObject = Object.assign(
{},
objectFromSetState1,
objectFromSetState2,
objectFromSetState3
);
이 때 3개의 객체가 동일한 키를 가지고 있다면, Object.assign
에 마지막으로 전달된 객체(objectFromSetState3
)의 키의 값만 적용됩니다.
해결방법
이 문제를 해결하기 위해서는 setState
함수에 새로운 state
를 반환하는 함수를 인자로 전달하면 됩니다.
이렇게 하면 인자로 넘겨 받는 함수들은 Queue에 저장되어 순서대로 실행되게 됩니다.
const [number, setNumber] = useState(1);
const add = () => setNumber(number => number + 1);
const subtract = () => setNumber(number => number - 1);
const multiplyBy2 = () => setNumber(number => number * 2);
const multiplyBy2AndAddBy1 = () => {
multiplyBy2();
add();
};