
useState: prev를 쓸까, state를 그대로 가져올까?리액트를 사용하다 보면 상태를 업데이트할 때 두 가지 방법을 자주 접한다.
// 1. 직접 상태를 이용하는 방법
setCount(count + 1);
// 2. 이전 상태(prev)를 이용하는 방법
setCount((prev) => prev + 1);
겉으로 보기에는 두 코드 모두 count 값을 1 증가시키는 것처럼 보이지만 리액트의 상태 업데이트 방식 때문에 이 두 가지 방법은 미묘한 차이를 가지고 있다.
setCount(count + 1);
이 방식은 단순히 현재 count 변수를 읽어서, 그 값에 1을 더해 새로운 상태를 설정.
하지만 리액트의 특징 중 하나가 상태 업데이트가 비동기적(asynchronous)이고, 이때문에 여러 개가 한 번에(batch) 처리될 수 있다
만약 이벤트 루프 내에서 여러 번 setCount(count + 1)을 호출한다면...?
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
개발자의 의도는 count가 3 증가하는 것일 거다.
그렇지만 실제로는 모든 호출이 동일한 초기 count 값을 기준으로 계산되어, 최종적으로는 단 1만 증가하게 되는 문제가 발생할 수 있다.
setCount((prev) => prev + 1);
이 방식은 setCount에 함수를 전달한다. 함수의 인자로는 항상 최신 상태(prev) 가 들어오기 때문에, 상태 업데이트가 비동기적이거나 여러 번 배치되더라도 안전하게 원하는 값으로 업데이트가 가능하다. 즉 아래의 예시에서
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
위 코드는 순차적으로 실행되어 count가 정확히 3 증가한다는 것!
결론은 상태를 기반으로 새로운 값을 계산해야 할 때는 prev 방식을 쓰는 것이 안정적 이라는 것이다.
현재 값으로 단순히 교체할 때
→ 직접 참조 (setState(value)) 방식을 사용해도 무방
예: setIsOpen(true)
이전 상태를 기반으로 새로운 값을 계산할 때
→ 반드시 prev 방식 (setState(prev => ...))을 쓰는 것이 안전
예: 카운터 증가, 토글, 누적 값 처리
React의 상태 업데이트는 동기적으로 즉시 반영되는 것이 아니라, 비동기적이고 배치 처리될 수 있다.
따라서 setState(count + 1) 방식은 간단하지만, 동시에 여러 번 호출될 경우 의도와 다른 결과가 나온다는 것. (버튼을 10번 동시에 눌러도 2가 될 수 있다ㅏㅏ)
반대로 setState(prev => prev + 1) 방식은 항상 최신 상태를 기준으로 동작하기 때문에, 여러 번의 상태 변경에도 안정적이다. (100번을 동시에 눌러도 문제 ㄴㄴ)
👉 결론: 이전 상태에 의존하는 연산이라면 반드시 prev를 사용하자!
setState 정도는 이제 자신 있다고 생각했지만 난 여전히 무지했고 오늘 하나 더 알아간다.
https://dev.to/harsh8088/avoiding-common-usestate-mistakes-in-react-3aao