useState
의 동작 원리를 이해하면 개발을 하는데 도움이 될 것 같아서 useState
동작 원리를 정리해보았다.
useState 동작 원리
useState
는 상태를 변경하기 위해 setState
를 호출하면, 호출 즉시 상태가 변경되지 않는다. 다시 말해서 비동기적(Asynchronous)으로 동작한다. 코드를 통해 자세히 살펴보자.
좋아요 버튼을 클릭하면 setLiked(liked + 1)
을 두 번 호출하게 handleClick
함수를 구현했다.
const App = () => {
const [liked, setLiked] = useState(0);
const handleClick = () => {
setLiked(liked + 1);
setLiked(liked + 1);
};
return (
<div>
<button onClick={handleClick}>좋아요 | {liked}</button>
</div>
);
}
export default App;
화면에서 보는것 처럼 liked
상태가 1씩 증가하는 모습을 확인할 수 있다. liked
의 상태가 1씩 증가하는 이유는 setState
는 동기로 처리하지 않고 배치(batch) 처리하기 때문이다.
배치 처리는 데이터를 실시간으로 처리하지 않고 한번에 모아서 처리하는 것을 의미한다.
리액트는 여러개의 state를 하나로 묶어서 처리한다. setLiked(liked + 1)
을 두 번 호출해도 이전의 값을 계속 덮어쓰기 때문에 한 번 호출한 것과 동일한 현상이 일어난다. 하나의 상태가 변경될때마다 계속 리렌더링을 한다면 성능상의 문제가 발생할 수 있기 때문에 리액트는 배치 처리한다. 따라서 useState
는 호출 즉시 동기적으로 상태가 변하는 것이 아니라 비동기적으로 동작한다.
useState 동기 처리
useState
를 동기적으로 처리할 수 있는 방법은 두 가지가 있다.
setState
사용 시 함수로 인자 전달useEffect
사용
다음은 setState
를 사용해서 동기적으로 처리하는 코드이다.
const App = () => {
const [liked, setLiked] = useState(0);
const handleClick = () => {
setLiked((liked) => liked + 1);
setLiked((liked) => liked + 1);
};
return (
<div>
<button onClick={handleClick}>좋아요 | {liked}</button>
</div>
);
}
export default App;
setState
를 사용할 때 value
값에 의존하는 것 보다 value => value + 1
과 같이 함수로 인자를 전달하게 되면 항상 최신값을 참조하기 때문에 동기적으로 처리할 수 있다.
리액트 18 버전에서는 Automatic Batching 기능이 추가되어서
setState
코드를 두 번 실행해도 두 번의 렌더링이 일어난다.
useEffect
는 적절한 예제를 찾지 못해서 설명으로 대체한다.useEffect
를 사용하면 의존성 배열에 값에 따라 이펙트(부수효과)가 실행되기 때문에, 동기적으로 처리할 수 있다.
댓글