v19.2Latest

스냅샷으로서의 State

State 변수는 읽고 쓸 수 있는 일반 JavaScript 변수처럼 보일 수 있습니다. 그러나 state는 스냅샷처럼 동작합니다. state를 설정한다고 해서 이미 존재하는 state 변수가 변경되는 것이 아니라, 대신 리렌더링을 촉발합니다.

배울 내용
  • state 설정이 리렌더링을 촉발하는 방법
  • state가 업데이트되는 시기와 방법
  • state를 설정한 직후에 즉시 업데이트되지 않는 이유
  • 이벤트 핸들러가 state의 "스냅샷"에 접근하는 방법

state 설정은 렌더링을 촉발합니다

사용자 인터페이스가 클릭과 같은 사용자 이벤트에 직접 반응하여 변경된다고 생각할 수 있습니다. React에서는 이 멘탈 모델과 약간 다르게 작동합니다. 이전 페이지에서 보셨듯이,state를 설정하면 React에 리렌더링을 요청하게 됩니다. 즉, 인터페이스가 이벤트에 반응하려면state를 업데이트해야 합니다.

이 예제에서 "send"를 누르면,setIsSent(true)가 React에게 UI를 리렌더링하라고 지시합니다:

버튼을 클릭할 때 발생하는 일은 다음과 같습니다:

  1. TheonSubmit이벤트 핸들러가 실행됩니다.
  2. setIsSent(true)isSenttrue로 설정하고 새로운 렌더링을 큐에 넣습니다.
  3. React는 새로운 isSent값에 따라 컴포넌트를 리렌더링합니다.

state와 렌더링의 관계를 자세히 살펴보겠습니다.

렌더링은 특정 시점의 스냅샷을 찍습니다

"렌더링"은 React가 컴포넌트(함수)를 호출하는 것을 의미합니다. 그 함수에서 반환하는 JSX는 특정 시점의 UI 스냅샷과 같습니다. 그 JSX의 props, 이벤트 핸들러, 로컬 변수는 모두렌더링 당시의 state를 사용하여 계산된 것입니다.

사진이나 영화 프레임과 달리, 여러분이 반환하는 UI "스냅샷"은 상호작용적입니다. 입력에 대한 응답으로 발생할 일을 지정하는 이벤트 핸들러와 같은 로직을 포함합니다. React는 이 스냅샷과 일치하도록 화면을 업데이트하고 이벤트 핸들러를 연결합니다. 결과적으로 버튼을 누르면 여러분의 JSX에 있는 클릭 핸들러가 트리거됩니다.

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

  1. React는 여러분의 함수를 다시 호출합니다.
  2. 여러분의 함수는 새로운 JSX 스냅샷을 반환합니다.
  3. 그런 다음 React는 여러분의 함수가 반환한 스냅샷과 일치하도록 화면을 업데이트합니다.
  1. 함수를 실행하는 React
  2. 스냅샷 계산하기
  3. DOM 트리 업데이트하기

일러스트:Rachel Lee Nabors

컴포넌트의 기억 장치로서, state는 함수가 반환된 후 사라지는 일반 변수와 다릅니다. state는 실제로 여러분의 함수 외부에서 React 자체 안에 "살아있습니다"—마치 선반 위에 있는 것처럼요! React가 여러분의 컴포넌트를 호출할 때, 해당 특정 렌더링을 위한 state의 스냅샷을 제공합니다. 여러분의 컴포넌트는 JSX 안에 새로운 props와 이벤트 핸들러 세트를 갖춘 UI의 스냅샷을 반환하는데, 이 모든 것은해당 렌더링의 state 값을 사용하여 계산됩니다!

  1. 여러분이 React에게 state 업데이트를 지시합니다
  2. React가 state 값을 업데이트합니다
  3. React가 state 값의 스냅샷을 컴포넌트에 전달합니다

일러스트:Rachel Lee Nabors

이것이 어떻게 작동하는지 보여주는 작은 실험입니다. 이 예제에서, 여러분은 "+3" 버튼을 클릭하면 카운터가 세 번 증가할 것으로 예상할 수 있습니다. 왜냐하면 그것이setNumber(number + 1)을 세 번 호출하기 때문입니다.

"+3" 버튼을 클릭하면 어떤 일이 발생하는지 확인하세요:

클릭할 때마다number가 한 번만 증가한다는 점을 확인하세요!

상태를 설정하는 것은 다음렌더링에서만 변경됩니다.첫 번째 렌더링에서number0이었습니다. 그래서그 렌더링의onClick 핸들러에서 number의 값은0으로 유지되며,setNumber(number + 1)가 호출된 후에도 마찬가지입니다:

다음은 이 버튼의 클릭 핸들러가 React에 지시하는 내용입니다:

  1. setNumber(number + 1):number0이므로setNumber(0 + 1)입니다.
    • React는 다음 렌더링에서number1로 변경할 준비를 합니다.
  2. setNumber(number + 1):number0이므로setNumber(0 + 1)입니다.
    • React는 다음 렌더링에서number1로 변경할 준비를 합니다.
  3. setNumber(number + 1):number0이므로setNumber(0 + 1)입니다.
    • React는 다음 렌더링에서number1로 변경할 준비를 합니다.

비록 setNumber(number + 1)를 세 번 호출했지만,이번 렌더링의이벤트 핸들러에서number는 항상0이므로 상태를 1로 세 번 설정하게 됩니다. 이것이 이벤트 핸들러가 완료된 후 React가 컴포넌트를number3이 아닌1과 같은 값으로 다시 렌더링하는 이유입니다.

코드에서 상태 변수를 그 값으로 대체해보면 이를 시각적으로 이해할 수도 있습니다.number상태 변수가0이므로, 해당 이벤트 핸들러는 다음과 같습니다:이번 렌더링에서

다음 렌더링에서는number1이므로,해당 렌더링의클릭 핸들러는 다음과 같습니다:

이것이 버튼을 다시 클릭하면 카운터가2로 설정되고, 다음 클릭에서는3로 설정되는 등의 이유입니다.

시간에 따른 상태

재미있었습니다. 이 버튼을 클릭하면 무엇이 경고창에 표시될지 맞춰보세요:

이전의 치환 방법을 사용하면, 경고창이 "0"을 표시한다고 추측할 수 있습니다:

하지만 경고창에 타이머를 설정해서, 컴포넌트가 다시 렌더링된후에만실행되도록 하면 어떨까요? "0"이라고 표시될까요, 아니면 "5"라고 표시될까요? 추측해 보세요!

놀랐나요? 치환 방법을 사용하면, 경고창에 전달된 상태의 "스냅샷"을 볼 수 있습니다.

경고창이 실행될 때쯤에는 React에 저장된 상태가 변경되었을 수 있지만, 그것은 사용자가 상호작용했을 때의 상태 스냅샷을 사용하여 예약된 것입니다!

상태 변수의 값은 한 번의 렌더링 내에서는 절대 변하지 않습니다,이벤트 핸들러의 코드가 비동기적이더라도 말이죠.그 렌더링의onClick내부에서는,setNumber(number + 5)가 호출된 후에도number의 값은 계속0입니다. 그 값은 React가 컴포넌트를 호출하여 UI의 "스냅샷을 찍었을" 때 "고정"된 것입니다.

이것이 어떻게 이벤트 핸들러가 타이밍 오류에 덜 취약하게 만드는지 예시를 들어보겠습니다. 아래는 5초 지연 후 메시지를 보내는 폼입니다. 이 시나리오를 상상해 보세요:

  1. "보내기" 버튼을 눌러 Alice에게 "Hello"를 보냅니다.
  2. 5초 지연이 끝나기 전에, "받는 사람" 필드의 값을 "Bob"으로 변경합니다.

경고창이 무엇을 표시할 것이라고 예상하시나요

React는 한 번의 렌더링의 이벤트 핸들러 내에서 상태 값을 "고정"된 상태로 유지합니다.코드가 실행되는 동안 상태가 변경되었는지 걱정할 필요가 없습니다.

하지만 다시 렌더링되기 전에 최신 상태를 읽고 싶다면 어떻게 해야 할까요? 다음 페이지에서 다룰상태 업데이터 함수를 사용하고 싶을 것입니다!

요약

  • 상태를 설정하는 것은 새로운 렌더링을 요청합니다.
  • React는 상태를 컴포넌트 외부, 마치 선반 위에 있는 것처럼 저장합니다.
  • 여러분이 useState를 호출하면, React는그 렌더링을 위한상태의 스냅샷을 제공합니다.
  • 변수와 이벤트 핸들러는 다시 렌더링해도 "살아남지" 않습니다. 모든 렌더링은 자신만의 이벤트 핸들러를 가집니다.
  • 모든 렌더링(그리고 그 안의 함수들)은 항상 React가렌더링에 제공한 상태의 스냅샷을 "볼" 것입니다.
  • 렌더링된 JSX에 대해 생각하는 방식과 유사하게, 이벤트 핸들러에서 상태를 머릿속에서 치환할 수 있습니다.
  • 과거에 생성된 이벤트 핸들러는 그들이 생성된 렌더링의 상태 값을 가집니다.

도전 과제를 시도해 보세요

Challenge 1 of 1:신호등 구현하기 #

버튼을 누르면 토글되는 횡단보도 신호등 컴포넌트입니다:

클릭 핸들러에 alert를 추가하세요. 신호등이 녹색이고 “Walk”라고 표시될 때 버튼을 클릭하면 “Stop is next”라고 표시되어야 합니다. 신호등이 빨간색이고 “Stop”이라고 표시될 때 버튼을 클릭하면 “Walk is next”라고 표시되어야 합니다.

alertsetWalk 호출 전에 놓는 것과 후에 놓는 것에 차이가 있나요?