https://react.dev/learn/state-as-a-snapshot 를 보고 정리한다.

 

State 변수는 스냅샷처럼 작동한다. state 값을 바꾸면 이미 가지고 있는 state를 변경하는 것이 아니라 리렌더링이 트리거된다.

state 설정은 렌더링을 일으킨다.

user interface는 사용자 이벤트에 대한 응답하기 위해 직접 변경된다고 생각할 수 있다.

하지만 React에서 멘탈 모델은 이와 다르다.

React에서는 state를 설정(변경)하면 리렌더링이 요청된다.(Rendering and Commit 참고)
즉, 인터페이스가 이벤트에 반응하려면 state를 업데이트 해야한다는 것을 의미한다.

아래 예제에서 "send" 버튼을 누르면 setIsSent(true)가 React에 UI를 리렌더링하도록 지시한다.

자세한 과정은 다음과 같다.

  1. onSubmit 이벤트 핸들러가 실행
  2. setInSent(true)isSenttrue로 설정하고 새로운 렌더를 큐에 넣음
  3. React는 새로운 isSent 값에 따라 컴포넌트를 리렌더링

렌더링은 그때그때의 스냅샷을 생성한다.

"렌더링" 은 React가 함수인 컴포넌트를 호출한다는 의미이다. 함수에서 반환하는 JSX는 해당 시점의 UI 스냅샷과 같다.

  • props, 이벤트 핸들러 및 지역 변수는 모두 렌더링 시점의 state를 사용하여 계산된다.
  • UI "스냅샷"은 상호작용을 한다.
    • 입력에 대한 응답을 지정하는 이벤트 핸들러와 같은 로직이 포함된다.
    • 그런 다음 React는 이 스냅샷과 일치하도록 화면을 업데이트하고 이벤트 핸들러를 연결한다.
    • 결과적으로 버튼을 누르면 JSX에서 클릭 핸들러가 발생된다.

 

React가 컴포넌트를 다시 렌더링할 때:

  1. React는 함수를 다시 호출
  2. 함수가 새 JSX 스냅샷을 반환
  3. React는 반환된 스냅샷과 일치하도록 화면을 업데이트

 

 

컴포넌트의 메모리에서 state는 함수가 반환된 후 사라지는 일반 변수와 다르다.

State는 함수 외부에 있는 것처럼 React 자체에 실제로 "살아 있다".

 

React가 컴포넌트를 호출하면 state 스냅샷을 제공한다.
컴포넌트는 해당 렌더링의 state 값을 사용하여
모두 계산된 JSX의 새로운 props 및 이벤트 핸들러 세트와 함께 UI의 스냅샷을 반환한다!

아래 예제는 "+3"버튼을 클릭하면 setNumber(number+1)을 세 번 호출하기 때문에 counter가 3번 증가할 것으로 예상할 수 있다.

하지만 결과는 클릭당 1번만 증가하게 된다.

그 이유는 state 설정시 다음 렌더링에 대해서만 변경되기 때문이다.

  • 초기 렌더링 : number = 0
  • 다음 렌더링 : number = 0 + 1
    • 3번 호출했지만 현재 렌더의 이벤트 핸들러가 가진 number는 항상 0이다.
    • 따라서 모든 setNumber(number+1) 는 현재(초기 렌더링)number가 0이기 때문에 다음 렌더링에서 number는 0 + 1 = 1 이 된다.

시간 경과에 따른 State

버튼 클릭시 alert될 내용을 추측해보자.

결과는 "0"가 나온다.

 

setTimeout을 주어도 동일하게 "0"이 나올 것이다.

setNumber(0 + 5);
setTimeout(() => {
  alert(0);
}, 3000);
state 변수의 값은 이벤트 핸들러가 비동기식인 경우에도 렌더 내에서 절대 변경되지 않는다.
즉, React가 컴포넌트를 호출하여 UI의 "스냅샷을 찍었을 때" 값이 "고정"된다.

 

다음은 이벤트 핸들러가 타이밍 실수를 덜하게 만드는 방법의 예다.

5초 지연 메시지를 보내는 form이며 아래의 시나리오를 상상해보자

  1. "Send" 버튼을 누르면 Alice에게 "Hello"가 전송됩니다.
  2. 5초 지연이 끝나기 전에 "To" 필드의 값을 "Bob"으로 변경합니다.

결과는 “You said Hello to Alice”가 나타난다.

이유는 위에서 말했다시피 React는 한 렌더의 이벤트 핸들러 내에서 상태 값을 "고정"으로 유지하기 때문이다.

 

+ Recent posts