Skip to content

Commit

Permalink
Translate : State as a snapshot (#642)
Browse files Browse the repository at this point in the history
* Translate : State as a snapshot

* fix : 리뷰 반영(어색한 표현 수정)

* fix : 리뷰 반영(문장 수정)

---------

Co-authored-by: Hyuntae EOM <hyunt0413@gmail.com>
  • Loading branch information
jinyoung234 and eomttt committed May 23, 2023
1 parent 59185bc commit c3be462
Showing 1 changed file with 52 additions and 50 deletions.
102 changes: 52 additions & 50 deletions src/content/learn/state-as-a-snapshot.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@ title: 스냅샷으로서의 State

<Intro>

State 변수는 읽고 쓸 수 있는 일반 자바스크립트 변수처럼 보일 수 있습니다. 그러나 state는 스냅샷 처럼 작동합니다. state를 설정하여도 이미 가지고 있는 state는 변경되지 않고, 대신에 다시 렌더링을 실행합니다.
State 변수는 읽고 쓸 수 있는 일반 자바스크립트 변수처럼 보일 수 있습니다. 하지만 state는 스냅샷처럼 동작합니다. state 변수를 설정하여도 이미 가지고 있는 state 변수는 변경되지 않고, 대신 리렌더링이 발동됩니다.

</Intro>

<YouWillLearn>

* state 설정이 어떻게 다시 렌더링을 실행하는지
* 언제 그리고 어떻게 state가 업데이트되는지
* state를 설정한 후에 왜 state값이 즉시 업데이트되지 않는지
* 이벤트 핸들러가 어떻게 state의 "스냅샷"에 접근하는지
* state 설정으로 리렌더링이 동작하는 방식
* state 업데이트 시기 및 방법
* state를 설정한 직후에 state가 업데이트되지 않는 이유
* 이벤트 핸들러가 state의 "스냅샷"에 접근하는 방법

</YouWillLearn>

## state를 설정하여 렌더링을 실행합니다. {/*setting-state-triggers-renders*/}
## state를 설정하면 렌더링이 동작합니다 {/*setting-state-triggers-renders*/}

You might think of your user interface as changing directly in response to the user event like a click. In React, it works a little differently from this mental model. On the previous page, you saw that [setting state requests a re-render](/learn/render-and-commit#step-1-trigger-a-render) from React. This means that for an interface to react to the event, you need to *update the state*.
클릭과 같은 사용자 이벤트에 반응하여 사용자 인터페이스가 직접 변경된다고 생각할 수 있습니다. React에서는 이 멘탈 모델과는 조금 다르게 작동합니다. 이전 페이지에서 [state를 설정하면 React에 리렌더링을 요청](/learn/render-and-commit#step-1-trigger-a-render)하는 것을 보았습니다. 즉, 인터페이스가 이벤트에 반응하려면 state를 업데이트해야 합니다.

예시에서 "전송" 버튼을 눌렀을 때, `setIsSent(true)`는 UI를 다시 렌더링하도록 React에 알려줍니다.

이 예시에서는 "send"를 누르면 `setIsSent(true)`는 React에 UI를 다시 렌더링하도록 지시합니다.

<Sandpack>

Expand Down Expand Up @@ -61,43 +62,44 @@ label, textarea { margin-bottom: 10px; display: block; }

</Sandpack>

버튼을 클릭하면 다음과 같이 됩니다.
버튼을 클릭하면 다음과 같은 일이 발생합니다.

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

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

## 렌더링은 적시에 스냅샷을 생성합니다. {/*rendering-takes-a-snapshot-in-time*/}
## 렌더링은 그 시점의 스냅샷을 찍습니다. {/*rendering-takes-a-snapshot-in-time*/}

["렌더링"](/learn/render-and-commit#step-2-react-renders-your-components)은 React가 함수 컴포넌트를 호출하는 것을 의미합니다. 함수에서 반환하는 JSX는 시간에 따른 UI의 스냅샷과 같습니다. 컴포넌트의 props, 이벤트 핸들러, 로컬 변수들 모두 계산됩니다. **렌더링 시점의 state 사용.**
["렌더링"](/learn/render-and-commit#step-2-react-renders-your-components)이란 React가 컴포넌트, 즉 함수를 호출한다는 뜻입니다. 해당 함수에서 반환하는 JSX는 시간상 UI의 스냅
샷과 같습니다. prop, 이벤트 핸들러, 로컬 변수는 모두 **렌더링 당시의 state를 사용해** 계산됩니다.

사진이나 동영상 프레임과 다르게 반환하는 UI "스냅샷"은 대화형입니다. 스냅샷은 입력에 대한 응답으로 발생하는 일을 지정하는 이벤트 핸들러와 같은 로직을 포함하고 있습니다. 그런 다음 React는 스냅샷과 일치하도록 화면을 업데이트하고 이벤트 핸들러를 연결합니다. 결과적으로 버튼을 누르면 JSX의 클릭 핸들러를 실행합니다.
사진이나 동영상 프레임과 달리 반환하는 UI "스냅샷"은 대화형입니다. 여기에는 입력에 대한 응답으로 어떤 일이 일어날지 지정하는 이벤트 핸들러와 같은 로직이 포함됩니다. 그러면 React는 스냅샷과 일치하도록 화면을 업데이트하고 이벤트 핸들러를 연결합니다. 결과적으로 버튼을 누르면 JSX의 클릭 핸들러가 발동됩니다.

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

1. React가 함수를 다시 호출합니다.
2. 함수가 JSX 스냅샷을 반환합니다.
3. 그런 다음 React는 반환된 스냅샷과 일치하도록 화면을 업데이트합니다.
2. 함수가 새로운 JSX 스냅샷을 반환합니다.
3. 그러면 React가 반환한 스냅샷과 일치하도록 화면을 업데이트합니다.

<IllustrationBlock title="다시 렌더링" sequential>
<Illustration caption="React가 함수를 호출합니다" src="/images/docs/illustrations/i_render1.png" />
<Illustration caption="스냅샷을 계산합니다" src="/images/docs/illustrations/i_render2.png" />
<Illustration caption="DOM tree를 업데이트 합니다" src="/images/docs/illustrations/i_render3.png" />
</IllustrationBlock>

컴포넌트의 메모리인 state는 함수가 반환된 후 사라지는 일반 변수와 다릅니다. 함수 외부에 있는 것처럼 실제로 React 자체에 "살아있는" State를 나타냅니다. React가 컴포넌트를 호출하면 특정 렌더링의 state에 대한 스냅샷을 제공합니다. 컴포넌트는 JSX에 새로운 props 및 이벤트 핸들러 세트가 있는 UI 스냅샷을 반환하며 모두 계산됩니다.**렌더링의 state 사용!**
컴포넌트의 메모리로써 state는 함수가 반환된 후 사라지는 일반 변수와 다릅니다. state는 실제로 함수 외부에 마치 선반에 있는 것처럼 React 자체에 “존재”합니다. React가 컴포넌트를 호출하면 특정 렌더링에 대한 state의 스냅샷을 제공합니다. 컴포넌트는 **해당 렌더링의 state 값을 사용해** 계산된 새로운 props 세트와 이벤트 핸들러가 포함된 UI의 스냅샷을 JSX에 반환합니다!

<IllustrationBlock sequential>
<Illustration caption="React에게 상태를 업데이트하라고 알립니다" src="/images/docs/illustrations/i_state-snapshot1.png" />
<Illustration caption="React는 state를 업데이트 합니다" src="/images/docs/illustrations/i_state-snapshot2.png" />
<Illustration caption="React는 state의 스냅샷을 컴포넌트에 전달합니다" src="/images/docs/illustrations/i_state-snapshot3.png" />
<Illustration caption="React에 state를 업데이트하라고 명령합니다" src="/images/docs/illustrations/i_state-snapshot1.png" />
<Illustration caption="React가 state 값을 업데이트 합니다" src="/images/docs/illustrations/i_state-snapshot2.png" />
<Illustration caption="React는 상태 값의 스냅샷을 컴포넌트에 전달합니다" src="/images/docs/illustrations/i_state-snapshot3.png" />
</IllustrationBlock>

이것이 어떻게 동작하는지 보여주기 위한 작은 실험이 있습니다. 이 예시에서, "+3"버튼을 클릭하면 `setNumber(number + 1)`를 세 번 호출하기 때문에 카운터가 세 번 증가할 것으로 예상할 수 있습니다.
다음은 이것이 어떻게 작동하는지 보여주는 간단한 실험입니다. 이 예제에서는 ‘+3’ 버튼을 클릭하면 `setNumber(number + 1)`를 세 번 호출하므로 카운터가 세 번 증가할 것으로 예상할 수 있습니다.

"+3" 버튼을 클릭하면 어떻게 되는지 확인해봅시다.
"+3" 버튼을 클릭하면 어떻게 되는지 확인해 봅시다.

<Sandpack>

Expand Down Expand Up @@ -127,9 +129,9 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }

</Sandpack>

`number`는 클릭당 한 번만 증가합니다!
`number`는 클릭당 한 번만 증가한다는 점에 유의하세요!

**state를 설정하면 *다음* 렌더링에 대해서만 변경됩니다.** 첫 번째 렌더링을 하는동안, `number``0` 이었습니다. 이것이 "첫 번째 렌더링의" `onClick`핸들러에서 `setNumber(number + 1)`가 호출된 후에도 `number`값이 여전히 `0`인 이유입니다.
**state를 설정하면 다음 렌더링에 대해서만 변경됩니다.** 첫 번째 렌더링에서 `number``0`이었습니다. 따라서 해당 렌더링의 `onClick` 핸들러에서 `setNumber(number + 1)`가 호출된 후에도 `number`값은 여전히 `0`입니다.

```js
<button onClick={() => {
Expand All @@ -139,18 +141,18 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
}}>+3</button>
```

다음은 버튼의 클릭 핸들러가 전달하는 React가 해야 할 일들입니다.
버튼의 클릭 핸들러가 React에 지시하는 작업은 다음과 같습니다.

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

`setNumber(number + 1)`를 세 번 호출했지만 *렌더링*이벤트 핸들러에서 `number`는 항상 `0`이므로 state를 `1`로 세 번 설정합니다. 이것이 이벤트 핸들러가 완료된 후 React가 '3'이 아닌 '1'과 같은 `number로 구성 요소를 다시 렌더링하는 이유입니다.
`setNumber(number + 1)`를 세 번 호출했지만, 이 렌더링에서 이벤트 핸들러에서 `number`는 항상 `0`이므로 state를 `1`로 세 번 설정합니다. 이것이 이벤트 핸들러가 완료된 후 React가 컴포넌트 안의 `number``3`이 아닌 `1` 다시 렌더링하는 이유입니다.

코드에서 state를 해당 값으로 이를 시각화할 수도 있습니다. *렌더링*의 경우 `number` state가 `0` 이므로 이벤트 핸들러는 다음과 같습니다.
코드에서 state 변수를 해당 값으로 대입하여 이를 시각화할 수도 있습니다. 이 렌더링에서 `number` state 변수는 `0`이므로 이벤트 핸들러는 다음과 같습니다.

```js
<button onClick={() => {
Expand All @@ -160,7 +162,7 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
}}>+3</button>
```

다음 렌더링의 경우 `number` `1`이므로 *렌더링의* 클릭 핸들러는 다음과 같습니다.
다음 렌더링에서는 `number` `1`이므로 렌더링의 클릭 핸들러는 다음과 같이 표시됩니다.

```js
<button onClick={() => {
Expand All @@ -170,11 +172,11 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
}}>+3</button>
```

이것이 버튼을 다시 클릭하면 카운터가 `2`로 설정되고 다음 클릭에서 `3`'으로 설정되는 방식인 이유입니다.
그렇기 때문에 버튼을 다시 클릭하면 카운터가 `2`로 설정되고, 다음 클릭 시에는 `3`으로 설정되는 방식입니다.

## 시간 경과에 따른 State {/*state-over-time*/}

정말 재밌죠. 이 버튼을 클릭하면 무엇을 경고할지 추측해 보세요.
재미있네요. 이 버튼을 클릭하면 어떤 경고창이 표시되는지 맞혀보세요.

<Sandpack>

Expand Down Expand Up @@ -210,7 +212,7 @@ setNumber(0 + 5);
alert(0);
```

그러나 경고창에 타이머를 설정하여 컴포넌트가 다시 렌더링 된 _이후에_ 실행하면 어떻게 될까요? "0" 또는 "5" 일까요? 추측해보세요!
하지만 경고창에 타이머를 설정하여 컴포넌트가 다시 렌더링 된 후에만 발동하도록 하면 어떨까요? “0” 또는 “5”라고 표시될까요? 맞춰보세요!

<Sandpack>

Expand Down Expand Up @@ -250,16 +252,16 @@ setTimeout(() => {
}, 3000);
```

React에 저장된 state는 경고창이 실행될 때 변경되었을 수 있지만 사용자가 상호 작용할 때 state의 스냅샷을 사용하여 예정되었습니다!
React에 저장된 state는 경고창이 실행될 때 변경되었을 수 있지만 사용자가 상호작용한 시점에 state 스냅샷을 사용하는 건 이미 예약되어 있던 것입니다!

이벤트 핸들러의 코드가 비동기적일지라도, **state 값은 렌더링 내에서 절대 변경되지 않습니다.** *렌더링의* `onClick` 내부에서 `setNumber(number + 5)`가 호출된 후에도 `number`의 값은 계속 `0`입니다. React가 컴포넌트를 호출하여 UI의 "스냅샷을 찍었을 때" 값이 "고정"되었습니다.
**state 변수의 값은** 이벤트 핸들러의 코드가 비동기적이더라도 **렌더링 내에서 절대 변경되지 않습니다.** 해당 렌더링의 `onClick` 내에서, `setNumber(number + 5)`가 호출된 후에도 `number`의 값은 계속 `0`입니다. 이 값은 컴포넌트를 호출해 React가 UI의 스냅샷을 찍을” 때 “고정”된 값입니다.

다음은 이벤트 핸들러가 타이밍 실수를 덜 하게 만드는 방법의 예시입니다. 다음은 5초 지연 메시지를 보내는 양식입니다. 이 시나리오를 상상해보세요.
다음은 이벤트 핸들러가 타이밍 실수를 줄이는 방법을 보여주는 예입니다. 아래는 5초 지연된 메시지를 보내는 양식입니다. 이 시나리오를 상상해 보세요.

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

`경고창`이 표시될 것으로 예상되는 내용은 무엇입니까? "앨리스에게 인사했습니다"가 표시될까요? 아니면 "밥에게 인사했습니다"라고 표시될까요? 알고 있는 내용을 바탕으로 추측한 다음 시도해 보세요.
`alert`에 어떤 내용이 표시되기를 기대하나요? “앨리스에게 인사했습니다”라고 표시될까요, 아니면 “당신은 밥에게 인사했습니다라고 표시될까요? 알고 있는 내용을 바탕으로 추측해보고, 다음의 코드를 실행해 보세요.

<Sandpack>

Expand Down Expand Up @@ -305,27 +307,27 @@ label, textarea { margin-bottom: 10px; display: block; }

</Sandpack>

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

그러나 다시 렌더링하기 전에 최신 state를 읽고 싶다면 어떻게 해야 할까요? 다음 페이지에서 다룰 [state 갱신 함수](/learn/queueing-a-series-of-state-updates)사용하고 싶을 것입니다.
하지만 다시 렌더링하기 전에 최신 state를 읽고 싶다면 어떻게 해야 할까요? 다음 페이지에서 설명하는 [state 갱신 함수](/learn/queueing-a-series-of-state-updates)사용하면 됩니다!

<Recap>

* state를 설정하면 새 렌더링이 요청됩니다
* React는 선반에 있는 것처럼 구성 요소 외부에 state를 저장합니다. (as if on a shelf)
* `useState`를 호출하면 React는 *렌더링*의 state에 대한 스냅샷을 제공합니다.
* 변수 및 이벤트 핸들러는 "생존"하여 다시 렌더링 되지 않습니다. 모든 렌더링에는 고유의 이벤트 핸들러가 있습니다.
* 모든 렌더링(및 그 안의 함수)은 항상 React가 **렌더링에 부여한 state의 스냅샷을 "볼" 것입니다.
* state를 설정하면 새 렌더링을 요청합니다.
* React는 컴포넌트 외부에 마치 선반에 보관하듯 state를 저장합니다.
* `useState`를 호출하면 React는 해당 렌더링에 대한 state의 스냅샷을 제공합니다.
* 변수와 이벤트 핸들러는 다시 렌더링해도 “살아남지” 않습니다. 모든 렌더링에는 고유한 이벤트 핸들러가 있습니다.
* 모든 렌더링(및 그 안의 함수)은 항상 React가 렌더링에 제공한 state의 스냅샷을 "보게" 됩니다.
* 렌더링 된 JSX에 대해 생각하는 방식과 유사하게 이벤트 핸들러에서 state를 대체할 수 있습니다.
* 과거에 생성된 이벤트 핸들러는 생성되었을 당시 렌더링의 state 값을 가집니다.
* 과거에 생성된 이벤트 핸들러는 그것이 생성된 렌더링 시점의 state 값을 갖습니다.

</Recap>



<Challenges>

#### 신호등을 구현해봅시다 {/*implement-a-traffic-light*/}
#### 신호등 구현하기 {/*implement-a-traffic-light*/}

다음은 버튼을 토글되는 신호등 컴포넌트입니다.

Expand Down Expand Up @@ -362,13 +364,13 @@ h1 { margin-top: 20px; }

</Sandpack>

클릭 핸들러에 `경고창`을 추가합니다. 신호등이 녹색이고 "Walk"라고 표시되면 버튼을 클릭하면 "Stop is next"라고 표시되어야 합니다. 표시등이 빨간색이고 "중지"라고 표시되면 버튼을 클릭하면 "다음은 걷기"라고 표시되어야 합니다.
클릭 핸들러에 `alert`를 추가하세요. 신호등이 녹색이고 "걷기"라고 표시되면 버튼을 클릭하면 "다음은 정지입니다"라고 표시되어야 합니다. 신호등이 빨간색이고 "중지"라고 표시되면 버튼을 클릭하면 "다음은 걷기입니다"라고 표시되어야 합니다.

`setWalk` 호출 전 또는 후에 `경고창`을 설정하는지에 차이가 있을까요?
`alert``setWalk` 호출 전이나 후에 넣는 것이 차이가 있을까요?

<Solution>

`경고창` 다음과 같아야 합니다.
`alert` 다음과 같이 작성해야 합니다.

<Sandpack>

Expand Down Expand Up @@ -404,15 +406,15 @@ h1 { margin-top: 20px; }

</Sandpack>

경고창을 `setWalk` 호출 전후에 배치하든 상관없이 차이가 없습니다. 렌더링의 `walk` 값은 고정되어 있습니다. `setWalk`를 호출하면 *다음* 렌더링에 대해서만 변경되지만, 이전 렌더링의 이벤트 핸들러에는 영향을 미치지 않습니다.
`setWalk` 호출 앞에 넣든, 뒤에 넣든 아무런 차이가 없습니다. 해당 렌더링의 `walk` 값은 고정되어 있습니다. `setWalk`를 호출하면 다음 렌더링에 대해서만 변경되고, 이전 렌더링의 이벤트 핸들러에는 영향을 미치지 않습니다.

이 라인은 처음에는 직관적이지 않게 보일 수 있습니다.

```js
alert(walk ? 'Stop is next' : 'Walk is next');
```

그러나 다음과 같이 읽는다면 의미가 있습니다. "신호등이 'Walk now'로 표시되면 메시지는 'Stop is next'라고 표시되어야 합니다." 이벤트 핸들러 내부의 `walk` 변수는 렌더링의 `walk` 값과 일치하고 변하지 않습니다.
하지만 이렇게 읽으면 이해가 될 것입니다. “신호등에 ‘Walk now’가 표시되면, 메시지에 ‘Stop is next.’라고, 표시되어야 합니다. 이벤트 핸들러 내부의 `walk` 변수는 해당 렌더링의 값인 `walk`와 일치하며 변경되지 않습니다.

대체 메서드를 적용하여 이것이 올바른지 확인할 수 있습니다. `walk``true`이면 다음과 같은 결과를 얻습니다.

Expand Down

0 comments on commit c3be462

Please sign in to comment.