처음 이 질문을 보자마자 들었던 생각은 '당연한거 아냐?' 였다.
State가 변경되면 React는 이를 감지해 리렌더링이 발생하고, 갱신된 state로 UI를 새로 그렸기 때문이다.
그러나 확신은 없었다. 이렇게 간단한 문제였으면 묻지도 않았을테니...
☝🏼 우선, 위의 질문에 답하기 위해서는 React 내부 동작 원리와 상태값 변경, 렌더링의 원리를 이해하고 있어야 할 것이다.
공식 문서를 보면, "setState()는 컴포넌트 state의 변경 사항을 대기열에 집어넣고, React에게 해당 컴포넌트와 그 자식들이 갱신된 state를 사용하여 다시 렌더링되어야 한다고 알립니다. 이 메서드는 이벤트 핸들러와 서버 응답 등에 따라 UI를 갱신할 때에 가장 많이 사용하는 메서드입니다." 라고 돼있다.
즉, setState()가 쓰일 때, 컴포넌트의 state 객체에 대한 업데이트
를 실행한다. state가 변경되면 컴포넌트는 리렌더링
된다.
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를 일괄적으로 업데이트하기 때문인데, 왜 그렇게 하는걸까?
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에 적용
한다.
setState() 함수는 인자로 새로운 state 객체를 인자를 받을 수도 있지만, 이전 state 값을 기준으로 값을 계산해야 한다면, 객체 대신 updater 함수
를 전달해야 한다.
updater 함수를 전달하면 updater 함수 안에서 이전 state 값에 접근할 수 있다.
setState 호출은 일괄적으로 처리되기 때문에 여러 업데이트 사항이 충돌 없이 차례대로 반영된다.
const onClick = () => {
setState((prevState) => prevState + 1);
setState((prevState) => prevState + 1);
setState((prevState) => prevState + 1);
};
위 코드로 수정하면, +1이 아닌 +3씩 증가하는 것을 볼 수 있다.
React의 setState가 비동기로 작동하는 이유는 렌더링 횟수를 줄여 더 빠르게 동작하게 하기 위함
인 것을 알 수 있다.
props와 state 사이의 일괄성을 해칠 수 있으며, 디버깅하기 힘든 이슈가 생길 수 있다.
※ 참고 자료
React 공식 문서
React - setState 이해하기
React - setState가 비동기인 이유
좋은 정보 얻어갑니다, 감사합니다.