state는 스냅샷
React의 useState Hook은 상태 변수와 업데이트 함수를 제공합니다. 상태를 변경하면 React는 컴포넌트를 재렌더링하며, 새로운 상태를 반영한 UI 스냅샷을 생성합니다. 그러나 현재 렌더링의 스냅샷은 고정되어 있으며, 이벤트 핸들러 내에서 상태 변경 함수가 호출되더라도 그 시점의 상태 값은 그대로 유지됩니다. 이는 상태가 각 렌더링의 사진처럼 캡처되어 사용됩니다.
import { useState } from 'react';
export default function ScoreBoard() {
const [score, setScore] = useState(0);
const handleScoreIncrease = () => {
setScore(score + 1);
setScore(score + 1);
setScore(score + 1);
// 현재 렌더링의 score는 여전히 0
console.log(`이벤트 핸들러 내 score: ${score}`);
};
return (
<div style={{ padding: '20px', border: '1px solid #ddd', borderRadius: '5px' }}>
<h2>점수: {score}</h2>
<button
onClick={handleScoreIncrease}
style={{ padding: '8px 16px', backgroundColor: '#007bff', color: 'white' }}
>
+1씩 3번 호출
</button>
</div>
);
}
- 호출 결과: setScore를 세 번 호출하지만, score는 첫 렌더링 시점의 값(0)을 기준으로 계산됩니다.
- 콘솔 출력: 벤트 핸들러 내 score: 0이 출력되고, 다음 렌더링에서 score는 1로 업데이트됩니다.
- 배치 처리: React는 여러 상태 업데이트를 하나의 렌더링으로 묶어 최적화하며, 동일한 값이 반복 호출되면 마지막 값만 적용됩니다.
상태 스냅샷과 비동기 작업
이벤트 핸들러가 실행될 때 캡처된 상태는 이후 업데이트와 관계없이 유지됩니다.
import { useState } from 'react';
export default function MessageSender() {
const [messageCount, setMessageCount] = useState(0);
const handleSendMessage = () => {
setMessageCount(messageCount + 1);
setTimeout(() => {
// 이 시점에서 UI는 이미 업데이트되었을 수 있지만,
// 캡처된 messageCount는 이전 값임
alert(`보낸 메시지 수 (핸들러 시점): ${messageCount}`);
}, 2000);
};
return (
<div style={{ padding: '20px', maxWidth: '400px', border: '1px solid #eee' }}>
<h2>보낸 메시지: {messageCount}</h2>
<button
onClick={handleSendMessage}
style={{ padding: '10px', backgroundColor: '#28a745', color: 'white' }}
>
메시지 보내기 (+1 후 2초 지연 알림)
</button>
</div>
);
}
- 상태 업데이트: setMessageCount로 messageCount가 증가하며 UI는 즉시 반영됩니다.
- 스냅샷 캡쳐: setTimeout 콜백은 버튼 클릭 시점의 messageCount(처음 클릭시 0)을 기억합니다.
- 결과: 2초 후 알림은 보낸 메시지 수 (핸들러 시점): 0을 표시하지만, 화면은 이미 1로 업데이트됩니다.
상태 스냅샷의 중요성
- 예측 가능성: 렌더링 시점의 상태가 고정되어, 동일한 입력에 동일한 출력 보장됩니다.
- 비동기 안정성: 비동기 콜백이 최신 상태에 의존하지 않고, 캡처된 스냅샷으로 동작됩니다.
- 배치 최적화: React는 상태 업데이트를 모아 한 번의 렌더링으로 처리해 성능 향상됩니다.
'REACT > 리액트 학습하기' 카테고리의 다른 글
[REACT] 렌더링과 커밋 과정: 화면에 나타나기까지의 3단계 (0) | 2025.03.14 |
---|---|
[REACT] 상태 관리: useState로 컴포넌트의 동적 메모리 활용하기 (0) | 2025.03.14 |
[REACT] 이벤트 핸들링 기법 (0) | 2025.03.14 |
[REACT] UI 트리 이해하기 (0) | 2025.03.13 |
[REACT] 컴포넌트의 최적화와 확장 (0) | 2025.03.13 |