counter.jsx라는 컴포넌트를 만들고 useState를 이용해 버튼을 클릭할 때마다 숫자가 1씩 증가하게 만들어보았다.
import React, { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div className="counter">
<span className="number">{count}</span>
<button
className="button"
onClick={() => {
setCount(count + 1);
}}
>
Add +
</button>
</div>
);
}
그런데 여기서 든 의문점 하나!
왜 setCount(count++)로 쓰면 에러가 날까?
그 이유는 위에서 count를 const로 선언해주었기 때문이다.
상수는 재할당이 안되기 때문에 count++ 이 아니라 count+1로 써줘야 한다!
count++은
count=count+1 과 같은 의미이다. 이는 곧 count를 재할당 해주는 것이기 때문에 에러가 나는 것이다!
그럼 여기서 또 하나의 의문점!
setCount를 다섯번 호출하면 count값이 5가 될까??
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
이건 js의 클로저(closure)개념과 관련이 있는데, 클로저란 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다. 이를 조금 더 간단히 말하면 클로저는 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수다!
onClick이 호출됐을 때 전달되는 콜백 함수가 호출될 때 찰칵! 하고 현재 상태를 스냅샷한다. 그 때 내부에서 사용되고 있는 count값인 0이 저장이 되고 그 때의 렉시컬 환경이 콜백 함수에 전달이 된다.
그래서 0+1은 1이 되고 아무리 setCount를 호출해도 1이 되는 것이다!
그렇다면 한번 add버튼을 클릭했을 때 바로 5가 되려면 어떻게 해야할까?
이전 값을 전달하는 콜백 함수를 사용하면 된다!
onClick={() => {
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
}}
setCount가 호출될 때 이전 상태값을 prev라는 콜백 인자로 전달받는다!
따라서 최종 setCount가 5로 설정되는 것이다!