( 2024-02-19 보완 )
배운 지 얼마 되지 않았을 때 상태 값을 업데이트하는 함수(예: 아래 예시의 setCount()
)가 호출될 때마다 즉시 함수 컴포넌트가 다시 실행되는 것이라 오해한 적이 있었다.
아래 실제 코드와 함께 동작을 알아보자.
+
버튼을 클릭할 때마다 카운트가 3
씩 증가하는 카운터를 구현한 코드다.
function Counter() {
console.log("Counter() 시작");
const [count, setCount] = React.useState(0);
console.log(`count: ${count}`);
const onClick = () => {
console.log("setCount() (1/3)");
setCount((cur) => {
console.log("count 1 증가 (1/3)");
return cur + 1;
});
console.log("setCount() (2/3)");
setCount((cur) => {
console.log("count 1 증가 (2/3)");
return cur + 1;
});
console.log("setCount() (3/3)");
setCount((cur) => {
console.log("count 1 증가 (3/3)");
return cur + 1;
});
};
console.log("Counter() 끝");
return (
<>
<h1>{count}</h1>
<button
onClick={onClick}
>
+
</button>
</>
);
}
[ 콘솔 출력 ]
Counter() 시작
count: 0
Counter() 끝
+
버튼 첫 번째 클릭setCount() (1/3)
count 1 증가 (1/3)
setCount() (2/3)
setCount() (3/3)
Counter() 시작
count 1 증가 (2/3)
count 1 증가 (3/3)
count: 3
Counter() 끝
+
버튼 두 번째 클릭setCount() (1/3)
setCount() (2/3)
setCount() (3/3)
Counter() 시작
count 1 증가 (1/3)
count 1 증가 (2/3)
count 1 증가 (3/3)
count: 6
Counter() 끝
+
버튼 세 번째 클릭setCount() (1/3)
setCount() (2/3)
setCount() (3/3)
Counter() 시작
count 1 증가 (1/3)
count 1 증가 (2/3)
count 1 증가 (3/3)
count: 9
Counter() 끝
Q. 위 출력 결과를 보고 무엇을 알 수 있을까?
A.
setCount()
함수를 호출하자마자 Counter()
컴포넌트가 즉시 다시 렌더링되는 것이 아니라 같은 스코프에 있는 setCount()
함수들을 전부 호출한 뒤에 렌더링이 시작된다.useState()
함수 호출 시점에 count
값이 변경된다. (그래서 useState()
를 컴포넌트 코드 최상단에 위치시켜야 하는 것이군)Q. 파라미터 cur
이 아니라 count
를 직접 변경하면 어떻게 될까?
const onClick = () => {
// setCount(count + 1);과 같음
setCount(() => {
return count + 1; // 파라미터 대신 count 기준 +1
});
setCount(() => {
return count + 1;
});
setCount(() => {
return count + 1;
});
};
A. 3씩 증가하는 게 아니라 1씩 증가한다.
count + 1
반환 전에 count
값을 출력해 보면 세 곳에서의 값이 같다. 즉, count
에 1 더한 값이 계속 반복 할당될 뿐이다.count
에 할당하는 것이라면 변경을 처리하는 동안 count
값에 변화가 없는 것은 당연하다.Q. setCount()
를 호출하지만 상태를 변경하지는 않는다면 어떻게 될까?
A. setCount()
를 호출하더라도 상태 변경이 없으면 함수 컴포넌트는 다시 렌더링 되지 않는다.
Q. 첫 번째 클릭만 출력이 다른 건 왜일까?
카운터를 두 개 만들어서 번갈아가며 클릭해 보면, 꼭 첫 번째 클릭이 아니더라도 직전에 다른 카운터의 버튼을 클릭했다면 첫 번째 클릭했을 때와 출력이 같던데, 흠..