diff --git a/src/content/learn/thinking-in-react.md b/src/content/learn/thinking-in-react.md
index 023a0e0dc..3e0159342 100644
--- a/src/content/learn/thinking-in-react.md
+++ b/src/content/learn/thinking-in-react.md
@@ -4,7 +4,7 @@ title: React로 사고하기
-React를 사용하게 되면 우리가 고려하고 있는 디자인이나 만들 앱들에 대한 생각을 바꿀 수 있습니다. React로 사용자 인터페이스를 빌드할 때, 먼저 이를 컴포넌트라는 조각으로 나눕니다. 그리고 각 컴포넌트의 다양한 시각적 상태들을 정의합니다. 마지막으로 컴포넌트들을 연결하여 데이터가 그 사이를 흘러가게 합니다. 이 자습서에서는 React로 검색할 수 있는 상품 테이블을 만드는 과정을 체계적으로 안내해 드리겠습니다.
+React를 사용하면 우리가 고려하고 있는 디자인이나 만들 앱에 대한 생각을 바꿀 수 있습니다. React로 사용자 인터페이스를 빌드할 때, 먼저 이를 컴포넌트라는 조각으로 나눕니다. 그리고 각 컴포넌트의 다양한 시각적 상태들을 정의합니다. 마지막으로 컴포넌트들을 연결하여 데이터가 그 사이를 흘러가게 합니다. 이 자습서에서는 React로 검색할 수 있는 상품 테이블을 만드는 과정을 체계적으로 안내해 드리겠습니다.
@@ -36,8 +36,8 @@ React로 UI를 구현하기 위해서 일반적으로 다섯 가지 단계를
어떤 배경을 가지고 있냐에 따라, 디자인을 컴포넌트로 나누는 방법에 대한 관점이 달라질 수 있습니다.
-* **Programming**--새로운 함수나 객체를 만드는 방식과 같은 방법으로 해봅시다. 이 중 [단일책임 원칙](https://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99)을 반영하고자 한다면 컴포넌트는 이상적으로는 한 번에 한 가지 일만 해야 합니다. 만약 컴포넌트가 점점 커진다면 작은 하위 컴포넌트로 쪼개져야 하겠죠.
-* **CSS**--클래스 선택자를 무엇으로 만들지 생각해 봅시다. (실제 컴포넌트들은 약간 좀 더 세분되어 있습니다.)
+* **Programming**--새로운 함수나 객체를 만드는 방식으로 해봅시다. 이 중 [단일 책임 원칙](https://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99)을 반영하고자 한다면 컴포넌트는 이상적으로는 한 번에 한 가지 일만 해야 합니다. 만약 컴포넌트가 점점 커진다면 작은 하위 컴포넌트로 쪼개져야 하겠죠.
+* **CSS**--클래스 선택자를 무엇으로 만들지 생각해 봅시다. (실제 컴포넌트들은 약간 더 세분되어 있습니다.)
* **Design**--디자인 계층을 어떤 식으로 구성할 지 생각해 봅시다.
JSON이 잘 구조화 되어있다면, 종종 이것이 UI의 컴포넌트 구조가 자연스럽게 데이터 모델에 대응된다는 것을 발견할 수 있습니다. 이는 UI와 데이터 모델은 보통 같은 정보 아키텍처, 즉 같은 구조를 가지기 때문입니다. UI를 컴포넌트로 분리하고, 각 컴포넌트가 데이터 모델에 매칭될 수 있도록 하세요.
@@ -72,11 +72,11 @@ JSON이 잘 구조화 되어있다면, 종종 이것이 UI의 컴포넌트 구
## Step 2: React로 정적인 버전 구현하기 {/*step-2-build-a-static-version-in-react*/}
-이제 컴포넌트 계층구조가 만들어졌으니, 앱을 실제로 구현해 볼 시간입니다. 가장 쉬운 접근 방법은 상호작용 기능은 아직 추가하지 않고 데이터 모델로부터 UI를 렌더링하는 버전을 만드는 것입니다. 대체로 먼저 정적인 버전을 만들고 상호작용 기능을 추가하는 게 더 쉽습니다. 정적 버전을 만드는 것은 많은 타이핑이 필요하지만, 생각할 것은 적으며, 반대로 상호작용 기능을 추가하는 것은 많은 생각이 필요하지만, 타이핑은 그리 많이 필요하지 않습니다.
+이제 컴포넌트 계층구조를 만들었으니, 앱을 실제로 구현해 볼 시간입니다. 가장 쉬운 접근 방법은 상호작용 기능은 아직 추가하지 않고 데이터 모델로부터 UI를 렌더링하는 버전을 만드는 것입니다. 대체로 먼저 정적인 버전을 만들고 상호작용 기능을 추가하는 게 더 쉽습니다. 정적 버전을 만드는 것은 많은 타이핑이 필요하지만, 생각할 것은 적으며, 반대로 상호작용 기능을 추가하는 것은 많은 생각이 필요하지만, 타이핑은 그리 많이 필요하지 않습니다.
-데이터 모델을 렌더링하는 앱의 정적인 버전을 만들기 위해 다른 컴포넌트를 재사용하고 [props](/learn/passing-props-to-a-component)를 이용하여 데이터를 넘겨주는 [컴포넌트](/learn/your-first-component)를 구현할 수 있습니다. props는 부모가 자식에게 데이터를 넘겨줄 때 사용할 수 있는 방법입니다. (혹시 [state](/learn/state-a-components-memory) 개념에 익숙하다고 해도 정적인 버전을 만드는 데는 state를 쓰지 마세요! state는 오직 상호작용을 위해, 즉 시간이 지남에 따라 데이터가 바뀌는 것에 사용합니다. 우리는 앱의 정적 버전을 만들고 있기 때문에 지금은 필요하지 않습니다.)
+데이터 모델을 렌더링하는 앱의 정적인 버전을 만들기 위해 다른 컴포넌트를 재사용하고 [Props](/learn/passing-props-to-a-component)를 이용하여 데이터를 넘겨주는 [컴포넌트](/learn/your-first-component)를 구현할 수 있습니다. Props는 부모가 자식에게 데이터를 넘겨줄 때 사용할 수 있는 방법입니다. (혹시 [State](/learn/state-a-components-memory) 개념에 익숙하다고 해도 정적인 버전을 만드는 데는 State를 쓰지 마세요! State는 오직 상호작용을 위해, 즉 시간이 지남에 따라 데이터가 바뀌는 것에 사용합니다. 우리는 앱의 정적 버전을 만들고 있기 때문에 지금은 필요하지 않습니다.)
-앱을 만들 때 계층 구조에 따라 상층부에 있는 컴포넌트 (즉 `FilterableProductTable`부터 시작하는 것)부터 하향식(top-down)으로 만들거나 혹은 하층부에 있는 컴포넌트 (`ProductRow`)부터 상향식(bottom-up)으로 만들 수 있습니다. 간단한 예시에서는 보통 하향식으로 만드는 게 쉽지만, 프로젝트가 커지면 상향식으로 만들고 테스트를 작성하면서 개발하기가 더 쉽습니다.
+앱을 만들 때 계층 구조에 따라 상층부에 있는 컴포넌트 (즉, `FilterableProductTable`부터 시작하는 것)부터 하향식Top-Down으로 만들거나 혹은 하층부에 있는 컴포넌트 (`ProductRow`)부터 상향식Bottom-Up으로 만들 수 있습니다. 간단한 예시에서는 보통 하향식으로 만드는 게 쉽지만, 프로젝트가 커지면 상향식으로 만들고 테스트를 작성하면서 개발하는 것이 더 쉽습니다.
@@ -194,21 +194,21 @@ td {
-(위 코드가 어렵게 느껴진다면, [Quick Start](/learn)를 먼저 참고하세요!)
+(위 코드가 어렵게 느껴진다면, [빠르게 시작하기](/learn)를 먼저 참고하세요!)
-이 단계가 끝나면 데이터 렌더링을 위해 만들어진 재사용 가능한 컴포넌트들의 라이브러리를 가지게 됩니다. 현재는 앱의 정적 버전이기 때문에 컴포넌트는 단순히 JSX만 리턴합니다. 계층구조의 최상단 컴포넌트 (FilterableProductTable)는 prop으로 데이터 모델을 받습니다. 이는 데이터가 최상단 컴포넌트부터 트리의 맨 아래까지 흘러가기 때문에 `단방향 데이터 흐름`이라고 부릅니다.
+이 단계가 끝나면 데이터 렌더링을 위해 만들어진 재사용 가능한 컴포넌트들의 라이브러리를 가지게 됩니다. 현재는 앱의 정적 버전이기 때문에 컴포넌트는 단순히 JSX만 리턴합니다. 계층구조의 최상단 컴포넌트 `FilterableProductTable`은 Prop으로 데이터 모델을 받습니다. 이는 데이터가 최상단 컴포넌트부터 트리의 맨 아래까지 흘러가기 때문에 단방향 데이터 흐름이라고 부릅니다.
-여기까지는 아직 state값을 쓰지 마세요. 다음 단계에서 사용할 겁니다!
+여기까지는 아직 State 값을 쓰지 마세요. 다음 단계에서 사용할 겁니다!
## Step 3: 최소한의 데이터만 이용해서 완벽하게 UI State 표현하기 {/*step-3-find-the-minimal-but-complete-representation-of-ui-state*/}
-UI를 상호작용(interactive)하게 만들려면 사용자가 기반 데이터 모델을 변경할 수 있게 해야 합니다. React는 *state*를 통해 기반 데이터 모델을 변경할 수 있게 합니다.
+UI를 상호작용Interactive하게 만들려면 사용자가 기반 데이터 모델을 변경할 수 있게 해야 합니다. React는 *State*를 통해 기반 데이터 모델을 변경할 수 있게 합니다.
-state는 앱이 기억해야 하는, 변경할 수 있는 데이터의 최소 집합이라고 생각하세요. state를 구조화하는 데 가장 중요한 원칙은 [중복배제원칙(Don't Repeat Yourself)](https://ko.wikipedia.org/wiki/%EC%A4%91%EB%B3%B5%EB%B0%B0%EC%A0%9C)입니다. 애플리케이션이 필요로 하는 가장 최소한의 state를 파악하고 나머지 모든 것들은 필요에 따라 실시간으로 계산하세요. 예를 들어, 쇼핑 리스트를 만든다고 하면 당신은 배열에 상품 아이템들을 넣을 겁니다. UI에 상품 아이템의 개수를 노출하고 싶다고 하면 상품 아이템 개수를 따로 state 값으로 가지는 게 아니라 단순하게 배열의 길이만 쓰면 됩니다.
+State는 앱이 기억해야 하는, 변경할 수 있는 데이터의 최소 집합이라고 생각하세요. State를 구조화하는 데 가장 중요한 원칙은 [중복 배제 원칙Don't Repeat Yourself](https://ko.wikipedia.org/wiki/%EC%A4%91%EB%B3%B5%EB%B0%B0%EC%A0%9C)입니다. 애플리케이션이 필요로 하는 가장 최소한의 State를 파악하고 나머지 모든 것들은 필요에 따라 실시간으로 계산하세요. 예를 들어, 쇼핑 리스트를 만든다고 하면 당신은 배열에 상품 아이템들을 넣을 겁니다. UI에 상품 아이템의 개수를 노출하고 싶다고 하면 상품 아이템 개수를 따로 State 값으로 가지는 게 아니라 단순하게 배열의 길이만 쓰면 됩니다.
예시 애플리케이션 내 데이터들을 생각해 봅시다. 애플리케이션은 다음과 같은 데이터를 가지고 있습니다.
@@ -217,62 +217,62 @@ state는 앱이 기억해야 하는, 변경할 수 있는 데이터의 최소
3. 체크박스의 값
4. 필터링된 제품 목록
-이 중 어떤 게 state가 되어야 할까요? 아래의 세 가지 질문을 통해 결정할 수 있습니다.
+이 중 어떤 게 State가 되어야 할까요? 아래의 세 가지 질문을 통해 결정할 수 있습니다.
-- **시간이 지나도 변하지 않나요?** 그러면 확실히 state가 아닙니다.
-- **부모로부터 props를 통해 전달됩니까?** 그러면 확실히 state가 아닙니다.
-- 컴포넌트 안의 다른 state나 props를 가지고 **계산 가능한가요?** 그렇다면 *절대로* state가 아닙니다!
+- **시간이 지나도 변하지 않나요?** 그러면 확실히 State가 아닙니다.
+- **부모로부터 Props를 통해 전달됩니까?** 그러면 확실히 State가 아닙니다.
+- 컴포넌트 안의 다른 State나 Props를 가지고 **계산 가능한가요?** 그렇다면 *절대로* State가 아닙니다!
-그 외 남는 건 아마 state일 겁니다.
+그 외 남는 건 아마 State일 겁니다.
위 데이터들을 다시 한번 순서대로 살펴봅시다.
-1. 제품의 원본 목록은 **props로 전달되었기 때문에 state가 아닙니다**.
-2. 사용자가 입력한 검색어는 시간이 지남에 따라 변하고, 다른 요소로부터 계산될 수 없기 때문에 state로 볼 수 있습니다.
-3. 체크박스의 값은 시간에 따라 바뀌고 다른 요소로부터 계산될 수 없기 때문에 state로 볼 수 있습니다
-4. 필터링된 제품 목록은 원본 제품 목록을 받아서 검색어와 체크박스의 값에 따라 **계산할 수 있으므로, 이는 state가 아닙니다.**
+1. 제품의 원본 목록은 **Props로 전달되었기 때문에 State가 아닙니다**.
+2. 사용자가 입력한 검색어는 시간에 따라 변하고, 다른 요소로부터 계산할 수 없기 때문에 State로 볼 수 있습니다.
+3. 체크박스의 값은 시간에 따라 바뀌고 다른 요소로부터 계산할 수 없기 때문에 State로 볼 수 있습니다.
+4. 필터링된 제품 목록은 원본 제품 목록을 받아서 검색어와 체크박스의 값에 따라 **계산할 수 있으므로, 이는 State가 아닙니다.**
-따라서, 검색어와 체크박스의 값만이 state입니다! 잘하셨습니다!
+따라서, 검색어와 체크박스의 값만이 State입니다! 잘하셨습니다!
#### Props vs State {/*props-vs-state*/}
-React는 props와 state라는 두 개의 데이터 "모델"이 존재합니다. 둘의 성격은 매우 다릅니다.
+React는 Props와 State라는 두 개의 데이터 "모델"이 존재합니다. 둘의 성격은 매우 다릅니다.
-- [**Props**는 함수를 통해 전달되는 인자 같은 성격을 가집니다.](/learn/passing-props-to-a-component) props는 부모 컴포넌트로부터 자식 컴포넌트로 데이터를 넘겨서 외관을 커스터마이징하게 해줍니다. 예를 들어, `Form`은 color라는 prop을 `Button`으로 보내서 `Button`을 내가 원하는 형태로 커스터마이징시킬 수 있습니다..
-- [**State**는 컴포넌트의 메모리 같은 성격을 가집니다.](/learn/state-a-components-memory) state는 컴포넌트가 몇몇 정보를 계속 따라갈 수 있게 해주고 변화하면서 상호작용(interaction)을 만들어 냅니다. 예를 들어, `Button`은 `isHovered`라는 state를 따라갈 것입니다.
+- [**Props**는 함수를 통해 전달되는 인자 같은 성격을 가집니다.](/learn/passing-props-to-a-component) Props는 부모 컴포넌트로부터 자식 컴포넌트로 데이터를 넘겨서 외관을 커스터마이징하게 해줍니다. 예를 들어, `Form`은 `color`라는 Prop을 `Button`으로 보내서 `Button`을 내가 원하는 형태로 커스터마이징할 수 있습니다.
+- [**State**는 컴포넌트의 메모리 같은 성격을 가집니다.](/learn/state-a-components-memory) State는 컴포넌트가 몇몇 정보를 계속 따라갈 수 있게 해주고 변화하면서 상호작용Interaction을 만들어 냅니다. 예를 들어, `Button`은 `isHovered`라는 State를 따라갈 것입니다.
-props와 state는 다르지만, 함께 동작합니다. state는 보통 부모 컴포넌트에 저장됩니다. ( 그래서 부모 컴포넌트는 그 state를 변경할 수 있습니다. ) 그리고 부모 컴포넌트는 state를 자식 컴포넌트에 props로서 전달합니다. 처음 봤을 때 둘의 차이를 잘 알기 어려워도 괜찮습니다. 약간 연습이 필요할 거예요!
+Props와 State는 다르지만, 함께 동작합니다. State는 보통 부모 컴포넌트에 저장합니다. (그래서 부모 컴포넌트는 그 State를 변경할 수 있습니다.) 그리고 부모 컴포넌트는 State를 자식 컴포넌트에 Props로서 전달합니다. 처음 봤을 때 둘의 차이를 잘 알기 어려워도 괜찮습니다. 약간 연습이 필요할 거예요!
## Step 4: State가 어디에 있어야 할 지 정하기 {/*step-4-identify-where-your-state-should-live*/}
-이제 앱에서 최소한으로 필요한 state를 결정했습니다. 다음으로는 어떤 컴포넌트가 이 state를 소유하고, 변경할 책임을 지게 할 지 정해야 합니다. React는 항상 컴포넌트 계층구조를 따라 부모에서 자식으로 데이터를 전달하는 단방향 데이터 흐름을 사용하는 것을 기억하세요! 앱을 구현하면서 어떤 컴포넌트가 state를 가져야 하는 지 바로 명확하지 않을 수 있습니다. 이 개념이 처음이라면 더 어려울 수 있습니다. 그러나 아래의 과정을 따라가면 해결할 수 있습니다.
+이제 앱에서 필요한 최소한의 State를 결정했습니다. 다음으로는 어떤 컴포넌트가 이 State를 소유하고, 변경할 책임을 지게 할 지 정해야 합니다. React는 항상 컴포넌트 계층구조를 따라 부모에서 자식으로 데이터를 전달하는 단방향 데이터 흐름을 사용하는 것을 기억하세요! 앱을 구현하면서 어떤 컴포넌트가 State를 가져야 하는 지 명확하지 않을 수 있습니다. 이 개념이 처음이라면 더 어려울 수 있습니다. 그러나 아래의 과정을 따라가면 해결할 수 있습니다.
-애플리케이션의 각 state에 대해서,
+애플리케이션의 각 State에 대해서,
-1. 해당 state를 기반으로 렌더링하는 모든 컴포넌트를 찾으세요.
-2. 그들의 가장 가까운 공통되는 부모 컴포넌트를 찾으세요. - 계층에서 모두를 포괄하는 상위 컴포넌트
-3. state가 어디에 위치 돼야 하는지 결정합시다
- 1. 대개, 공통 부모에 state를 그냥 두면 됩니다.
- 2. 혹은, 공통 부모 상위의 컴포넌트에 둬도 됩니다.
- 3. state를 소유할 적절한 컴포넌트를 찾지 못하였다면, state를 소유하는 컴포넌트를 하나 만들어서 상위 계층에 추가하세요.
+1. 해당 State를 기반으로 렌더링하는 모든 컴포넌트를 찾으세요.
+2. 그들의 가장 가까운 공통되는 부모 컴포넌트를 찾으세요. 계층에서 모두를 포괄하는 상위 컴포넌트입니다.
+3. State가 어디에 위치해야 하는지 결정합니다.
+ 1. 대개, 공통 부모에 State를 그냥 두면 됩니다.
+ 2. 혹은, 공통 부모 상위 컴포넌트에 둬도 됩니다.
+ 3. State를 소유할 적절한 컴포넌트를 찾지 못했다면, State를 소유하는 컴포넌트를 하나 만들어서 상위 계층에 추가하세요.
-이전 단계에서, 이 애플리케이션의 두 가지 state인 사용자의 검색어 입력과 체크박스의 값을 발견하였습니다. 이 예시에서 그들은 항상 함께 나타나기 때문에 같은 위치에 두는 것이 합리적입니다.
+이전 단계에서, 이 애플리케이션의 두 가지 State인 사용자의 검색어 입력과 체크 박스의 값을 발견하였습니다. 이 예시에서 그들은 항상 함께 나타나기 때문에 같은 위치에 두는 것이 합리적입니다.
이제 이 전략을 애플리케이션에 적용해 봅시다.
-1. **state를 쓰는 컴포넌트를 찾아봅시다**:
- - `ProductTable`은 state에 기반한 상품 리스트를 필터링해야 합니다 (검색어와 체크 박스의 값)
- - `SearchBar`는 state를 표시해 주어야 합니다. (검색어와 체크 박스의 값)
-2. **공통 부모를 찾아봅시다**: 둘 모두가 공유하는 첫 번째 부모는 `FilterableProductTable`입니다
-3. **어디에 state가 존재해야 할지 정해봅시다**: 우리는`FilterableProductTable`에 검색어와 체크 박스 값을 state로 둘 겁니다.
+1. **State를 쓰는 컴포넌트를 찾아봅시다**:
+ - `ProductTable`은 State에 기반한 상품 리스트를 필터링해야 합니다. (검색어와 체크 박스의 값)
+ - `SearchBar`는 State를 표시해 주어야 합니다. (검색어와 체크 박스의 값)
+2. **공통 부모를 찾아봅시다**: 둘 모두가 공유하는 첫 번째 부모는 `FilterableProductTable`입니다.
+3. **어디에 State가 존재해야 할지 정해봅시다**: 우리는`FilterableProductTable`에 검색어와 체크 박스 값을 State로 둘 겁니다.
-이제 state 값은 `FilterableProductTable`안에 있습니다.
+이제 State 값은 `FilterableProductTable` 안에 있습니다.
-[`useState()` Hook](/reference/react/useState)을 이용해서 state를 컴포넌트에 추가하세요. Hooks는 React 기능에 "연결할 수(hook into)" 있게 해주는 특별한 함수입니다. `FilterableProductTable`의 상단에 두 개의 state 변수를 추가해서 초깃값을 명확하게 보여주세요.
+[`useState()` Hook](/reference/react/useState)을 이용해서 State를 컴포넌트에 추가하세요. Hook은 React 기능에 "연결할 수Hook Into" 있게 해주는 특별한 함수입니다. `FilterableProductTable`의 상단에 두 개의 State 변수를 추가해서 초깃값을 명확하게 보여주세요.
```js
function FilterableProductTable({ products }) {
@@ -280,7 +280,7 @@ function FilterableProductTable({ products }) {
const [inStockOnly, setInStockOnly] = useState(false);
```
-다음으로, `filterText`와 `inStockOnly`를 `ProductTable`와 `SearchBar`에게 props로 전달하세요.
+다음으로, `filterText`와 `inStockOnly`를 `ProductTable`와 `SearchBar`에게 Props로 전달하세요.
```js
@@ -433,7 +433,7 @@ td {
-아직 폼을 수정하는 작업이 작동하지 않음을 유의하세요. 위의 샌드박스에서 콘솔 에러가 발생하고 그 이유를 설명하겠습니다.
+아직 폼을 수정하는 작업이 작동하지 않음에 유의하세요. 위 샌드박스에서 콘솔 에러가 발생하며, 그 이유를 설명하겠습니다.
@@ -441,7 +441,7 @@ You provided a \`value\` prop to a form field without an \`onChange\` handler. T
-위에 있는 샌드박스를 보면, `ProductTable`와 `SearchBar`가 `filterText`와 `inStockOnly` props를 table, input과 체크 박스를 렌더링하기 위해서 읽고 있습니다. 예를 들면, `SearchBar` input의 value를 아래와 같이 채우고 있습니다.
+위에 있는 샌드박스를 보면, `ProductTable`과 `SearchBar`가 `filterText`와 `inStockOnly` Props를 표Table, 입력창Input, 체크 박스를 렌더링하기 위해서 읽고 있습니다. 예를 들면, `SearchBar` 입력창의 `value`를 아래와 같이 채우고 있습니다.
```js {1,6}
function SearchBar({ filterText, inStockOnly }) {
@@ -457,13 +457,13 @@ function SearchBar({ filterText, inStockOnly }) {
## Step 5: 역 데이터 흐름 추가하기 {/*step-5-add-inverse-data-flow*/}
-지금까지 우리는 계층 구조 아래로 흐르는 props와 state의 함수로써 앱을 만들었습니다. 이제 사용자 입력에 따라 state를 변경하려면 반대 방향의 데이터 흐름을 만들어야 합니다. 이를 위해서는 계층 구조의 하단에 있는 컴포넌트에서 `FilterableProductTable`의 state를 업데이트할 수 있어야 합니다.
+지금까지 우리는 계층 구조 아래로 흐르는 Props와 State의 함수로써 앱을 만들었습니다. 이제 사용자 입력에 따라 State를 변경하려면 반대 방향의 데이터 흐름을 만들어야 합니다. 이를 위해서는 계층 구조의 하단에 있는 컴포넌트에서 `FilterableProductTable`의 State를 업데이트할 수 있어야 합니다.
React는 데이터 흐름을 명시적으로 보이게 만들어 줍니다. 그러나 이는 전통적인 양방향 데이터 바인딩보다 조금 더 많은 타이핑이 필요합니다.
-4단계의 예시에서 체크하거나 키보드를 타이핑할 경우 UI의 변화가 없고 입력을 무시하는 것을 확인할 수 있습니다. 이건 의도적으로 ``로 코드를 쓰면서 `value`라는 prop이 항상`FilterableProductTable`의 `filterText`라는 state를 통해서 데이터를 받도록 정했기 때문입니다. `filterText`라는 state가 변경되는 게 아니기 때문에 input의 `value`는 변하지 않고 화면도 바뀌는 게 없습니다.
+4단계의 예시에서 체크하거나 키보드를 타이핑할 경우 UI의 변화가 없고 입력을 무시하는 것을 확인할 수 있습니다. 이건 의도적으로 ``로 코드를 쓰면서 `value`라는 Prop이 항상`FilterableProductTable`의 `filterText`라는 State를 통해서 데이터를 받도록 정했기 때문입니다. `filterText`라는 State가 변경되는 게 아니기 때문에 input의 `value`는 변하지 않고 화면도 바뀌는 게 없습니다.
-우리는 사용자가 input을 변경할 때마다 사용자의 입력을 반영할 수 있도록 state를 업데이트하기를 원합니다. state는 `FilterableProductTable`이 가지고 있고 state 변경을 위해서는 `setFilterText`와 `setInStockOnly`를 호출을 하면 됩니다. `SearchBar`가 `FilterableProductTable`의 state를 업데이트할 수 있도록 하려면, 이 함수들을 `SearchBar`로 전달해야 합니다.
+우리는 사용자가 input을 변경할 때마다 사용자의 입력을 반영할 수 있도록 State를 업데이트하기를 원합니다. State는 `FilterableProductTable`이 가지고 있고 State 변경을 위해서는 `setFilterText`와 `setInStockOnly`를 호출을 하면 됩니다. `SearchBar`가 `FilterableProductTable`의 State를 업데이트할 수 있도록 하려면, 이 함수들을 `SearchBar`로 전달해야 합니다.
```js {2,3,10,11}
function FilterableProductTable({ products }) {
@@ -479,7 +479,7 @@ function FilterableProductTable({ products }) {
onInStockOnlyChange={setInStockOnly} />
```
-`SearchBar`에서 `onChange` 이벤트 핸들러를 추가하여 부모 state를 변경할 수 있도록 구현할 수 있습니다.
+`SearchBar`에서 `onChange` 이벤트 핸들러를 추가하여 부모 State를 변경할 수 있도록 구현할 수 있습니다.
```js {4,5,13,19}
function SearchBar({
@@ -653,8 +653,8 @@ td {
-[Adding Interactivity](/learn/adding-interactivity) 섹션에서 state를 변경하고 이벤트를 다루는 것에 대해 더 심화해서 배울 수 있습니다.
+[상호작용 추가하기](/learn/adding-interactivity) 섹션에서 State를 변경하고 이벤트를 다루는 것에 대해 더 깊이있게 배울 수 있습니다.
## 더 나아가기 {/*where-to-go-from-here*/}
-지금까지는 React를 이용해서 컴포넌트와 앱을 만들려고 할 때 어떻게 사고할지에 대한 간단한 소개입니다. [당장 React로 프로젝트를 시작](/learn/installation)해도 좋고 다음 단계로 넘어가서 이 [자습서를 이용해서 좀 더 심화](/learn/describing-the-ui) 학습해도 좋습니다.
+지금까지는 React를 이용해서 컴포넌트와 앱을 만들려고 할 때 어떻게 사고할지에 대해 간단히 소개했습니다. [당장 React로 프로젝트를 시작](/learn/installation)해도 좋고 다음 단계로 넘어가서 이 [자습서를 이용해서 좀 더 심화](/learn/describing-the-ui) 학습해도 좋습니다.
diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md
index 1acc01fa4..efee3557e 100644
--- a/src/content/learn/tutorial-tic-tac-toe.md
+++ b/src/content/learn/tutorial-tic-tac-toe.md
@@ -18,7 +18,7 @@ title: '자습서: 틱택토 게임'
자습서는 아래와 같이 몇 가지 부문으로 나뉩니다.
- [자습서 환경설정](#setup-for-the-tutorial)은 자습서를 따를 수 있는 **시작점**을 제공합니다.
-- [개요](#overview)에서는 React의 **핵심**(컴포넌트, props, state)을 배울 수 있습니다.
+- [개요](#overview)에서는 React의 **핵심**(컴포넌트, Props, State)을 배울 수 있습니다.
- [게임 완료하기](#completing-the-game)에서는 React 개발에서 **가장 흔히 쓰이는 기술**을 배울 수 있습니다.
- [시간여행 추가하기](#adding-time-travel)에서는 React의 고유한 강점에 대해 **더 깊은 통찰력**을 얻을 수 있습니다.
@@ -207,7 +207,7 @@ body {
## 자습서 환경설정 {/*setup-for-the-tutorial*/}
-아래의 실시간 코드 편집기에서 오른쪽 위의 **Fork** 버튼을 클릭하여 새 탭에서 CodeSandBox 편집기를 열어주세요. CodeSandBox를 사용하면 브라우저에서 코드를 작성할 수 있으며 사용자가 만든 앱이 어떻게 보이는지 즉시 확인할 수 있습니다. 새 탭에는 텅 빈 사각형과 이 자습서의 시작 코드가 표시되어야 합니다.
+아래의 실시간 코드 편집기에서 오른쪽 위의 **포크Fork** 버튼을 클릭하여 새 탭에서 CodeSandBox 편집기를 열어주세요. CodeSandBox를 사용하면 브라우저에서 코드를 작성할 수 있으며 사용자가 만든 앱이 어떻게 보이는지 즉시 확인할 수 있습니다. 새 탭에는 텅 빈 사각형과 이 자습서의 시작 코드가 표시되어야 합니다.
@@ -308,7 +308,7 @@ _브라우저_ 구역에 아래와 같이 X가 있는 사각형이 표시되어
#### `App.js` {/*appjs*/}
-`App.js`의 코드는 _컴포넌트_ 를 생성합니다. React에서 컴포넌트는 사용자 인터페이스 일부를 표시하는 재사용 가능한 코드의 조각입니다. 컴포넌트는 애플리케이션의 UI 엘리먼트를 렌더링, 관리, 업데이트할 때 사용합니다. 컴포넌트를 한 줄씩 살펴보면서 무슨 일이 일어나는지 알아보겠습니다.
+`App.js`의 코드는 컴포넌트를 생성합니다. React에서 컴포넌트는 사용자 인터페이스 일부를 표시하는 재사용 가능한 코드 조각입니다. 컴포넌트는 애플리케이션의 UI 엘리먼트를 렌더링, 관리, 업데이트할 때 사용합니다. 컴포넌트를 한 줄씩 살펴보면서 무슨 일이 일어나는지 알아보겠습니다.
```js {1}
export default function Square() {
@@ -316,7 +316,7 @@ export default function Square() {
}
```
-첫 번째 줄은 `Square` 함수를 정의합니다. JavaScript의 `export` 키워드는 이 함수를 파일 외부에서 접근할 수 있도록 만들어 줍니다. `default` 키워드는 코드를 사용하는 다른 파일에서 이 함수가 파일의 주요 함수임을 알려줍니다.
+첫 번째 줄은 `Square` 함수를 정의합니다. 자바스크립트의 `export` 키워드는 이 함수를 파일 외부에서 접근할 수 있도록 만들어 줍니다. `default` 키워드는 코드를 사용하는 다른 파일에서 이 함수가 파일의 주요 함수임을 알려줍니다.
```js {2}
export default function Square() {
@@ -324,10 +324,10 @@ export default function Square() {
}
```
-두 번째 줄은 버튼을 반환합니다. JavaScript의 `return` 키워드는 해당 키워드 뒤에 오는 모든 것이 함수 호출자에게 값으로 반환됨을 의미합니다. ``은 JSX 엘리먼트를 닫아 버튼 내부에 다음 콘텐츠를 배치해서는 안 됨을 나타냅니다.
+두 번째 줄은 버튼을 반환합니다. 자바스크립트의 `return` 키워드는 해당 키워드 뒤에 오는 모든 것이 함수 호출자에게 값으로 반환됨을 의미합니다. ``은 JSX 엘리먼트를 닫아 버튼 내부에 다음 콘텐츠를 배치해서는 안 됨을 나타냅니다.
#### `styles.css` {/*stylescss*/}
-CodeSandBox의 _파일_ 구역에서 `styles.css` 파일을 여세요. 이 파일은 React 앱의 스타일을 정의합니다. 처음 두 개의 _CSS 선택자_ 인 `*`와 `body`는 앱 대부분의 스타일을 정의하고, `.square` 선택자는 `className` 프로퍼티가 `square`로 설정된 모든 컴포넌트의 스타일을 정의합니다. 초기 코드에서는 `App.js` 파일의 Square 컴포넌트의 버튼과 매치됩니다.
+CodeSandBox의 _파일_ 구역에서 `styles.css` 파일을 여세요. 이 파일은 React 앱의 스타일을 정의합니다. 처음 두 개의 CSS 선택자인 `*`와 `body`는 앱 대부분의 스타일을 정의하고, `.square` 선택자는 `className` 프로퍼티가 `square`로 설정된 모든 컴포넌트의 스타일을 정의합니다. 초기 코드에서는 `App.js` 파일의 `Square` 컴포넌트의 버튼과 매치됩니다.
#### `index.js` {/*indexjs*/}
@@ -370,7 +370,7 @@ export default function Square() {
-React 컴포넌트는 두 개의 버튼처럼 인접한 여러 개의 JSX 엘리먼트가 아닌 단일 JSX 엘리먼트를 반환해야 합니다. 이 오류는 *Fragments*(`<>` 와 `>`)를 사용하여 다음과 같이 여러 개의 인접한 JSX 엘리먼트를 감싸 해결할 수 있습니다.
+React 컴포넌트는 두 개의 버튼처럼 인접한 여러 개의 JSX 엘리먼트가 아닌 단일 JSX 엘리먼트를 반환해야 합니다. 이 오류는 *Fragment*(`<>` 와 `>`)를 사용하여 다음과 같이 여러 개의 인접한 JSX 엘리먼트를 감싸 해결할 수 있습니다.
```js {3-6}
export default function Square() {
@@ -419,7 +419,7 @@ export default function Square() {
}
```
-`styles.css` 에 정의된 CSS는 `board-row`라는 `className`으로 지정된 div를 스타일 합니다. 이제 스타일된 div를 사용하여 컴포넌트를 행으로 그룹화하여 틱택토 보드를 완성하겠습니다.
+`styles.css` 에 정의된 CSS는 `board-row`라는 `className`으로 지정된 `div`를 스타일 합니다. 이제 스타일된 `div`를 사용하여 컴포넌트를 행으로 그룹화하여 틱택토 보드를 완성하겠습니다.

@@ -512,7 +512,7 @@ body {
-### props를 통해 데이터 전달하기 {/*passing-data-through-props*/}
+### Props를 통해 데이터 전달하기 {/*passing-data-through-props*/}
다음으로 사용자가 사각형을 클릭할 때 사각형의 값을 비어있는 상태에서 "X"로 변경해야 합니다. 조금 전 보드를 만들었던 방법으로는 사각형을 변경하는 코드를 9번 (각 사각형당 한번) 복사해서 붙여 넣어야 합니다! 복사-붙여넣기 대신 React의 컴포넌트 아키텍처를 사용하면 재사용할 수 있는 컴포넌트를 만들어서 지저분하고 중복된 코드를 피할 수 있습니다.
@@ -528,7 +528,7 @@ export default function Board() {
}
```
-다음으로, Board 컴포넌트를 JSX 문법을 사용하여 해당 `Square` 컴포넌트를 렌더링하도록 수정하세요.
+다음으로, `Board` 컴포넌트를 JSX 문법을 사용하여 해당 `Square` 컴포넌트를 렌더링하도록 수정하세요.
```js {5-19}
// ...
@@ -561,9 +561,9 @@ export default function Board() {

-이런! 이전에 가지고 있던 번호가 채워진 사각형이 사라졌습니다. 이제 각 사각형은 "1"로 표시됩니다. 이 문제를 해결하기 위해 *props*를 사용하여 각 사각형이 가져야 할 값을 부모 컴포넌트(`Board`)에서 자식 컴포넌트(`Square`)로 전달하겠습니다.
+이런! 이전에 가지고 있던 번호가 채워진 사각형이 사라졌습니다. 이제 각 사각형은 "1"로 표시됩니다. 이 문제를 해결하기 위해 *Props*를 사용하여 각 사각형이 가져야 할 값을 부모 컴포넌트(`Board`)에서 자식 컴포넌트(`Square`)로 전달하겠습니다.
-`Square` 컴포넌트를 `Board`에서 전달할 prop `value`를 읽도록 수정하세요.
+`Square` 컴포넌트를 `Board`에서 전달할 Prop `value`를 읽도록 수정하세요.
```js {1}
function Square({ value }) {
@@ -571,7 +571,7 @@ function Square({ value }) {
}
```
-`function Square({ value })`는 사각형 컴포넌트에 `value` prop를 전달할 수 있음을 나타냅니다.
+`function Square({ value })`는 사각형 컴포넌트에 `value` Prop를 전달할 수 있음을 나타냅니다.
이제 모든 사각형에 `1` 대신 `value`를 표시하겠습니다. 아래와 같이 해보세요.
@@ -585,7 +585,7 @@ function Square({ value }) {

-컴포넌트에서 단어 "value"가 아닌 JavaScript 변수 `value`가 렌더링 되어야 합니다. JSX에서 "JavaScript로 탈출"하려면, 중괄호가 필요합니다. JSX에서 `value` 주위에 중괄호를 다음과 같이 추가하세요.
+컴포넌트에서 단어 "value"가 아닌 자바스크립트 변수 `value`가 렌더링 되어야 합니다. JSX에서 "자바스크립트로 탈출"하려면, 중괄호가 필요합니다. JSX에서 `value` 주위에 중괄호를 다음과 같이 추가하세요.
```js {2}
function Square({ value }) {
@@ -597,7 +597,7 @@ function Square({ value }) {

-보드가 비어있는 이유는 `Board` 컴포넌트가 렌더링하는 각 `Square` 컴포넌트에 아직 `value` prop를 전달하지 않았기 때문입니다. 이 문제를 해결하기 위해 `Board` 컴포넌트가 렌더링하는 각 `Square` 컴포넌트에 `value` prop를 추가하겠습니다.
+보드가 비어있는 이유는 `Board` 컴포넌트가 렌더링하는 각 `Square` 컴포넌트에 아직 `value` Prop를 전달하지 않았기 때문입니다. 이 문제를 해결하기 위해 `Board` 컴포넌트가 렌더링하는 각 `Square` 컴포넌트에 `value` Prop를 추가하겠습니다.
```js {5-7,10-12,15-17}
export default function Board() {
@@ -708,7 +708,7 @@ body {
### 사용자와 상호작용하는 컴포넌트 만들기 {/*making-an-interactive-component*/}
-이제 `Square` 컴포넌트를 클릭하면 `X`로 채워보겠습니다. `Square` 내부에 `handleClick` 함수를 선언하세요. 그런 다음 `Square` 컴포넌트에서 반환된 JSX 버튼의 props에 `onClick`을 추가하세요.
+이제 `Square` 컴포넌트를 클릭하면 `X`로 채워보겠습니다. `Square` 내부에 `handleClick` 함수를 선언하세요. 그런 다음 `Square` 컴포넌트에서 반환된 JSX 버튼의 Props에 `onClick`을 추가하세요.
```js {2-4,9}
function Square({ value }) {
@@ -735,11 +735,11 @@ function Square({ value }) {
-다음으로 사각형 컴포넌트가 클릭 된 것을 "기억"하고 "X" 표시로 채워보겠습니다. 컴포넌트는 무언가 "기억"하기 위해 *state*를 사용합니다.
+다음으로 사각형 컴포넌트가 클릭된 것을 "기억"하고 "X" 표시로 채워보겠습니다. 컴포넌트는 무언가 "기억"하기 위해 *State*를 사용합니다.
-React는 컴포넌트에서 호출하여 무언가를 "기억"할 수 있는 `useState`라는 특별한 함수를 제공합니다. `Square`의 현재 값을 state에 저장하고 `Square`가 클릭 되면 값을 변경해 보도록 하겠습니다.
+React는 컴포넌트에서 호출하여 무언가를 "기억"할 수 있는 `useState`라는 특별한 함수를 제공합니다. `Square`의 현재 값을 State에 저장하고 `Square`를 클릭하면 값을 변경하도록 하겠습니다.
-파일 상단에서 `useState`를 불러오세요. `Square` 컴포넌트에서 value prop을 제거하는 대신, `Square` 컴포넌트의 시작 부분에 `useState`를 호출하는 새 줄을 추가하고 `value`라는 이름의 state 변수를 반환하도록 하세요.
+파일 상단에서 `useState`를 불러오세요. `Square` 컴포넌트에서 `value` Prop을 제거하는 대신, `Square` 컴포넌트의 시작 부분에 `useState`를 호출하는 새 줄을 추가하고 `value`라는 이름의 State 변수를 반환하도록 하세요.
```js {1,3,4}
import { useState } from 'react';
@@ -751,9 +751,9 @@ function Square() {
//...
```
-`value`는 값을 저장하고 `setValue`는 값을 변경하는 데 사용하는 함수입니다. `useState`에 전달된 `null`은 이 state 변수의 초깃값으로 사용되므로 현재 `value`는 `null`과 같습니다.
+`value`는 값을 저장하고 `setValue`는 값을 변경하는 데 사용하는 함수입니다. `useState`에 전달된 `null`은 이 State 변수의 초깃값으로 사용되므로 현재 `value`는 `null`과 같습니다.
-`Square` 컴포넌트는 더 이상 props를 허용하지 않으므로 보드 컴포넌트가 생성한 9개의 사각형 컴포넌트에서 `value` prop를 제거하세요.
+`Square` 컴포넌트는 더 이상 Props를 허용하지 않으므로 `Board` 컴포넌트가 생성한 9개의 사각형 컴포넌트에서 `value` Prop를 제거하세요.
```js {6-8,11-13,16-18}
// ...
@@ -780,7 +780,7 @@ export default function Board() {
}
```
-이제 `Square`가 클릭 되었을 때 "X"를 표시하도록 변경하겠습니다. `console.log("clicked!");` 이벤트 핸들러를 `setValue('X');`로 변경하세요. 이제 `Square` 컴포넌트는 다음과 같습니다.
+이제 `Square`를 클릭하였을 때 "X"를 표시하도록 변경하겠습니다. `console.log("clicked!");` 이벤트 핸들러를 `setValue('X');`로 변경하세요. 이제 `Square` 컴포넌트는 다음과 같습니다.
```js {5}
function Square() {
@@ -801,11 +801,11 @@ function Square() {
}
```
-`onClick` 핸들러에서 `set` 함수를 호출함으로써 React에 `
-이제 각 사각형은 `'X'` , `'O'` , 또는 빈 사각형의 경우 `null`이 되는 `value` prop를 받습니다.
+이제 각 사각형은 `'X'` , `'O'` , 또는 빈 사각형의 경우 `null`이 되는 `value` Prop를 받습니다.
-다음으로 `Square`가 클릭 되었을 때 발생하는 동작을 변경하겠습니다. 이제 `Board` 컴포넌트가 어떤 사각형이 채워졌는지를 관리하므로 `Square`가 `Board`의 state를 업데이트할 방법을 만들어야 합니다. 컴포넌트는 자신이 정의한 state에만 접근할 수 있으므로 `Square`에서 `Board`의 state를 직접 변경할 수 없습니다.
+다음으로 `Square`를 클릭하였을 때 발생하는 동작을 변경하겠습니다. 이제 `Board` 컴포넌트가 어떤 사각형이 채워졌는지를 관리하므로 `Square`가 `Board`의 State를 업데이트할 방법을 만들어야 합니다. 컴포넌트는 자신이 정의한 State에만 접근할 수 있으므로 `Square`에서 `Board`의 State를 직접 변경할 수 없습니다.
-대신에 `Board` 컴포넌트에서 `Square` 컴포넌트로 함수를 전달하고 사각형이 클릭 될 때 `Square` 가 해당 함수를 호출하도록 할 수 있습니다. `Square` 컴포넌트가 클릭 될 때 호출할 함수부터 시작하겠습니다. `onSquareClick`으로 해당 함수를 호출하세요.
+대신에 `Board` 컴포넌트에서 `Square` 컴포넌트로 함수를 전달하고 사각형을 클릭할 때 `Square`가 해당 함수를 호출하도록 할 수 있습니다. `Square` 컴포넌트를 클릭할 때 호출할 함수부터 시작하겠습니다. `onSquareClick`으로 해당 함수를 호출하세요.
```js {3}
function Square({ value }) {
@@ -1086,7 +1086,7 @@ function Square({ value }) {
}
```
-다음으로, `Square` 컴포넌트의 props에 `onSquareClick` 함수를 추가하세요.
+다음으로, `Square` 컴포넌트의 Props에 `onSquareClick` 함수를 추가하세요.
```js {1}
function Square({ value, onSquareClick }) {
@@ -1098,7 +1098,7 @@ function Square({ value, onSquareClick }) {
}
```
-이제 `onSquareClick` prop을 `Board` 컴포넌트의 `handleClick` 함수와 연결하세요. `onSquareClick` 함수를 `handleClick`과 연결하려면 첫 번째 `Square` 컴포넌트의 `onSquareClick` prop에 해당 함수를 전달하면 됩니다.
+이제 `onSquareClick` Prop을 `Board` 컴포넌트의 `handleClick` 함수와 연결하세요. `onSquareClick` 함수를 `handleClick`과 연결하려면 첫 번째 `Square` 컴포넌트의 `onSquareClick` Prop에 해당 함수를 전달하면 됩니다.
```js {7}
export default function Board() {
@@ -1113,7 +1113,7 @@ export default function Board() {
}
```
-마지막으로 보드 컴포넌트 내부에 `handleClick` 함수를 정의하여 보드의 state를 담고 있는 `squares` 배열을 업데이트하세요.
+마지막으로 보드 컴포넌트 내부에 `handleClick` 함수를 정의하여 보드의 State를 담고 있는 `squares` 배열을 업데이트하세요.
```js {4-8}
export default function Board() {
@@ -1131,13 +1131,13 @@ export default function Board() {
}
```
-`handleClick` 함수는 JavaScript의 `slice()` 배열 메서드를 사용하여 `squares` 배열의 사본 `nextSquares`를 생성합니다. 그런 다음 `handleClick` 함수는 `nextSquares` 배열의 첫 번째 사각형(인덱스 `[0]`)에 `X`를 추가하여 업데이트합니다.
+`handleClick` 함수는 자바스크립트의 `slice()` 배열 메서드를 사용하여 `squares` 배열의 사본 `nextSquares`를 생성합니다. 그런 다음 `handleClick` 함수는 `nextSquares` 배열의 첫 번째 사각형(인덱스 `[0]`)에 `X`를 추가하여 업데이트합니다.
-`setSquares` 함수를 호출하면 React는 컴포넌트의 state가 변경되었음을 알 수 있습니다. 그러면 `squares`의 state를 사용하는 컴포넌트(`Board`)와 그 하위 컴포넌트(보드를 구성하는 `Square` 컴포넌트)가 다시 렌더링 됩니다.
+`setSquares` 함수를 호출하면 React는 컴포넌트의 State가 변경되었음을 알 수 있습니다. 그러면 `squares`의 State를 사용하는 컴포넌트(`Board`)와 그 하위 컴포넌트(보드를 구성하는 `Square` 컴포넌트)가 다시 렌더링 됩니다.
-JavaScript는 [클로저](https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures)를 지원하므로 내부 함수가(예: `handleClick`) 외부 함수(예: `Board`)에 정의된 변수 및 함수에 접근할 수 있습니다. `handleClick` 함수는 `squares`의 state를 읽고 `setSquares` 메서드를 호출할 수 있는데, 이 두 함수는 `Board` 함수 내부에 정의되어 있기 때문입니다.
+자바스크립트는 [클로저](https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures)를 지원하므로 내부 함수가(예: `handleClick`) 외부 함수(예: `Board`)에 정의된 변수 및 함수에 접근할 수 있습니다. `handleClick` 함수는 `squares`의 State를 읽고 `setSquares` 메서드를 호출할 수 있는데, 이 두 함수는 `Board` 함수 내부에 정의되어 있기 때문입니다.
@@ -1159,13 +1159,13 @@ export default function Board() {
}
```
-다음으로 인수 `i`를 `handleClick`에 전달해야 합니다. 사각형의 `onSquareClick` prop를 아래와 같이 JSX에서 직접 `handleClick(0)`으로 설정할 수도 있지만 이 방법은 작동하지 않습니다.
+다음으로 인수 `i`를 `handleClick`에 전달해야 합니다. 사각형의 `onSquareClick` Prop를 아래와 같이 JSX에서 직접 `handleClick(0)`으로 설정할 수도 있지만 이 방법은 작동하지 않습니다.
```jsx
```
-이유는 다음과 같습니다. `handleClick(0)` 호출은 보드 컴포넌트 렌더링의 일부가 됩니다. `handleClick(0)`은 `setSquares`를 호출하여 보드 컴포넌트의 state를 변경하기 때문에 보드 컴포넌트 전체가 다시 렌더링 됩니다. 하지만 이 과정에서 `handleClick(0)`은 다시 실행되기 때문에 무한 루프에 빠지게 됩니다.
+이유는 다음과 같습니다. `handleClick(0)` 호출은 보드 컴포넌트 렌더링의 일부가 됩니다. `handleClick(0)`은 `setSquares`를 호출하여 보드 컴포넌트의 State를 변경하기 때문에 보드 컴포넌트 전체가 다시 렌더링 됩니다. 하지만 이 과정에서 `handleClick(0)`은 다시 실행되기 때문에 무한 루프에 빠지게 됩니다.
@@ -1175,9 +1175,9 @@ Too many re-renders. React limits the number of renders to prevent an infinite l
왜 이러한 문제가 더 일찍 발생하지 않았을까요?
-이전에 `onSquareClick={handleClick}`을 전달할 땐 함수를 *호출*한 것이 아니라 `handleClick` 함수를 prop로 전달했기 때문입니다. 하지만 지금은 `handleClick(0)`의 괄호를 보면 알 수 있듯이 해당 함수를 호출하고 있으므로 해당 함수가 너무 일찍 실행됩니다. 사용자가 클릭하기 전까지 `handleClick` 함수를 호출하면 *안 됩*니다!
+이전에 `onSquareClick={handleClick}`을 전달할 땐 함수를 *호출*한 것이 아니라 `handleClick` 함수를 Prop로 전달했기 때문입니다. 하지만 지금은 `handleClick(0)`의 괄호를 보면 알 수 있듯이 해당 함수를 호출하고 있으므로 해당 함수가 너무 일찍 실행됩니다. 사용자가 클릭하기 전까지 `handleClick` 함수를 호출하면 *안 됩*니다!
-이 문제를 해결하려면 `handleClick(0)`을 호출하는 `handleFirstSquareClick` 함수를 만들고, `handleClick(1)`을 호출하는 `handleSecondSquareClick`을 만들고… 계속해서 만들면 됩니다. 그리고 아까와 같이 호출하는 대신 `onSquareClick={handleFirstSquareClick}`와 같은 함수를 prop로 전달 해 주면 됩니다. 이렇게 하면 무한 루프를 해결할 수 있습니다.
+이 문제를 해결하려면 `handleClick(0)`을 호출하는 `handleFirstSquareClick` 함수를 만들고, `handleClick(1)`을 호출하는 `handleSecondSquareClick`을 만들고… 계속해서 만들면 됩니다. 그리고 아까와 같이 호출하는 대신 `onSquareClick={handleFirstSquareClick}`와 같은 함수를 Prop로 전달 해 주면 됩니다. 이렇게 하면 무한 루프를 해결할 수 있습니다.
하지만 9개의 서로 다른 함수를 정의하고 각각에 이름을 붙이는 것은 너무 장황합니다. 대신 이렇게 해보겠습니다.
@@ -1193,7 +1193,7 @@ export default function Board() {
}
```
-새로운 문법 `() =>`에 주목하세요. 여기서 `() => handleClick(0)`은 *화살표 함수*로, 함수를 짧게 정의하는 방법입니다. 사각형이 클릭 되면 `=>` "화살표" 뒤의 코드가 실행되어 `handleClick(0)`을 호출합니다.
+새로운 문법 `() =>`에 주목하세요. 여기서 `() => handleClick(0)`은 *화살표 함수*로, 함수를 짧게 정의하는 방법입니다. 사각형을 클릭하면 `=>` "화살표" 뒤의 코드가 실행되어 `handleClick(0)`을 호출합니다.
이제 전달한 화살표 함수에서 `handleClick`을 호출하도록 나머지 8개의 사각형 컴포넌트를 수정해야 합니다. `handleClick`을 호출할 때 인수가 올바른 사각형의 인덱스에 해당하는지 확인하세요.
@@ -1226,7 +1226,7 @@ export default function Board() {

-하지만 이번에는 모든 state 관리가 사각형이 아닌 `Board` 컴포넌트에서 처리됩니다!
+하지만 이번에는 모든 State 관리를 사각형이 아닌 `Board` 컴포넌트에서 처리합니다!
코드는 다음과 같습니다.
@@ -1321,27 +1321,27 @@ body {
-이제 `Board`가 모든 state를 관리하므로 부모 `Board` 컴포넌트는 자식 `Square` 컴포넌트가 올바르게 표시될 수 있도록 props를 전달합니다. `Square`를 클릭하면 자식 `Square` 컴포넌트가 부모 `Board` 컴포넌트에 보드의 state를 업데이트하도록 요청합니다. `Board`의 state가 변경되면 `Board` 컴포넌트와 모든 자식 `Square` 컴포넌트가 자동으로 다시 렌더링 됩니다. `Board` 컴포넌트에 속한 모든 사각형의 state를 유지하면 나중에 승자를 결정할 수 있습니다.
+이제 `Board`가 모든 State를 관리하므로 부모 `Board` 컴포넌트는 자식 `Square` 컴포넌트가 올바르게 표시될 수 있도록 Props를 전달합니다. `Square`를 클릭하면 자식 `Square` 컴포넌트가 부모 `Board` 컴포넌트에 보드의 State를 업데이트하도록 요청합니다. `Board`의 State가 변경되면 `Board` 컴포넌트와 모든 자식 `Square` 컴포넌트가 자동으로 다시 렌더링 됩니다. `Board` 컴포넌트에 속한 모든 사각형의 State를 유지하면 나중에 승자를 결정할 수 있습니다.
사용자가 보드의 왼쪽 위 사각형을 클릭하여 `X`를 추가하면 어떤 일이 발생하는지 다시 한번 정리해 보겠습니다.
-1. 왼쪽 위 사각형을 클릭하면 `button`이 `Square`로부터 `onClick` prop로 받은 함수가 실행됩니다. `Square` 컴포넌트는 보드에서 해당 함수를 `onSquareClick` props로 받았습니다. `Board` 컴포넌트는 JSX에서 해당 함수를 직접 정의했습니다. 이 함수는 `0`을 인수로 `handleClick`을 호출합니다.
+1. 왼쪽 위 사각형을 클릭하면 `button`이 `Square`로부터 `onClick` Prop로 받은 함수가 실행됩니다. `Square` 컴포넌트는 보드에서 해당 함수를 `onSquareClick` Props로 받았습니다. `Board` 컴포넌트는 JSX에서 해당 함수를 직접 정의했습니다. 이 함수는 `0`을 인수로 `handleClick`을 호출합니다.
1. `handleClick`은 인수 `0`을 사용하여 `squares` 배열의 첫 번째 엘리먼트를 `null`에서 `X`로 업데이트합니다.
-1. `Board` 컴포넌트의 `squares` state가 업데이트되어 `Board`와 그 모든 자식이 다시 렌더링 됩니다. 이에 따라 인덱스가 `0`인 `Square` 컴포넌트의 `value` prop가 `null`에서 `X`로 변경됩니다.
+1. `Board` 컴포넌트의 `squares` State가 업데이트되어 `Board`와 그 모든 자식이 다시 렌더링 됩니다. 이에 따라 인덱스가 `0`인 `Square` 컴포넌트의 `value` Prop가 `null`에서 `X`로 변경됩니다.
최종적으로 사용자는 왼쪽 위 사각형을 클릭한 후 비어있는 사각형이 `X`로 변경된 것을 확인할 수 있습니다.
-DOM `` 엘리먼트의 `onClick` 어트리뷰트는 빌트인 컴포넌트이기 때문에 React에서 특별한 의미를 갖습니다. 사용자 정의 컴포넌트, 예를 들어 사각형의 경우 이름은 사용자가 원하는 대로 지을 수 있습니다. `Square`의 `onSquareClick` prop나 `Board`의 `handleClick` 함수에 어떠한 이름을 붙여도 코드는 동일하게 작동합니다. React에서는 주로 이벤트를 나타내는 prop에는 `onSomething`과 같은 이름을 사용하고, 이벤트를 처리하는 함수를 정의 할 때는 `handleSomething`과 같은 이름을 사용합니다.
+DOM `` 엘리먼트의 `onClick` 어트리뷰트는 빌트인 컴포넌트이기 때문에 React에서 특별한 의미를 갖습니다. 사용자 정의 컴포넌트, 예를 들어 사각형의 경우 이름은 사용자가 원하는 대로 지을 수 있습니다. `Square`의 `onSquareClick` Prop나 `Board`의 `handleClick` 함수에 어떠한 이름을 붙여도 코드는 동일하게 작동합니다. React에서는 주로 이벤트를 나타내는 Prop에는 `onSomething`과 같은 이름을 사용하고, 이벤트를 처리하는 함수를 정의 할 때는 `handleSomething`과 같은 이름을 사용합니다.
### 불변성이 왜 중요할까요 {/*why-immutability-is-important*/}
-`handleClick`에서 기존 배열을 수정하는 대신 `.slice()`를 호출하여 `squares` 배열의 사본을 생성하는 방법에 주목하세요. 그 이유를 설명하기 위해 불변성과 불변성을 배우는 것이 중요한 이유에 대해 논의해 보겠습니다.
+`handleClick`에서 기존 배열을 수정하는 대신 `.slice()`를 호출하여 `squares` 배열의 사본을 생성하는 방식에 주목해주세요. 그 이유를 설명하기 위해 불변성과 불변성을 배우는 것이 중요한 이유에 대해 논의해 보겠습니다.
-일반적으로 데이터를 변경하는 방법에는 두 가지가 있습니다. 첫 번째 방법은 데이터의 값을 직접 변경하여 데이터를 _변형_ 하는 것입니다. 두 번째 방법은 원하는 변경 사항이 있는 새 복사본으로 데이터를 대체하는 것입니다. 다음은 `squares` 배열을 변형한 경우의 모습입니다.
+일반적으로 데이터를 변경하는 방법에는 두 가지가 있습니다. 첫 번째 방법은 데이터의 값을 직접 변경하여 데이터를 변형하는 것입니다. 두 번째 방법은 원하는 변경 사항이 있는 새 복사본으로 데이터를 대체하는 것입니다. 다음은 `squares` 배열을 변형한 경우의 모습입니다.
```jsx
const squares = [null, null, null, null, null, null, null, null, null];
@@ -1361,13 +1361,13 @@ const nextSquares = ['X', null, null, null, null, null, null, null, null];
불변성을 사용하면 복잡한 기능을 훨씬 쉽게 구현할 수 있습니다. 우리는 이 자습서의 뒷부분에서 게임의 진행 과정을 검토하고 과거 움직임으로 "돌아가기"를 할 수 있는 "시간 여행" 기능을 구현할 예정입니다. 특정 작업을 실행 취소하고 다시 실행하는 기능은 이 게임에만 국한된 것이 아닌 앱의 일반적인 요구사항입니다. 직접적인 데이터 변경을 피하면 이전 버전의 데이터를 그대로 유지하여 나중에 재사용(또는 초기화)할 수 있습니다.
-불변성을 사용하는 것의 또 다른 장점이 있습니다. 기본적으로 부모 컴포넌트의 state가 변경되면 모든 자식 컴포넌트가 자동으로 다시 렌더링 됩니다. 여기에는 변경 사항이 없는 자식 컴포넌트도 포함됩니다. 리렌더링 자체가 사용자에게 보이는 것은 아니지만 성능상의 이유로 트리의 영향을 받지 않는 부분의 리렌더링을 피하는 것이 좋습니다. 불변성을 사용하면 컴포넌트가 데이터의 변경 여부를 저렴한 비용으로 판단할 수 있습니다. [`memo` API 참고서](/reference/react/memo)에서 React가 컴포넌트를 다시 렌더링할 시점을 선택하는 방법에 대해 살펴볼 수 있습니다.
+불변성을 사용하는 것의 또 다른 장점이 있습니다. 기본적으로 부모 컴포넌트의 State가 변경되면 모든 자식 컴포넌트가 자동으로 다시 렌더링 됩니다. 여기에는 변경 사항이 없는 자식 컴포넌트도 포함됩니다. 리렌더링 자체가 사용자에게 보이는 것은 아니지만 성능상의 이유로 트리의 영향을 받지 않는 부분의 리렌더링을 피하는 것이 좋습니다. 불변성을 사용하면 컴포넌트가 데이터의 변경 여부를 저렴한 비용으로 판단할 수 있습니다. [`memo` API 참고서](/reference/react/memo)에서 React가 컴포넌트를 다시 렌더링할 시점을 선택하는 방법에 대해 살펴볼 수 있습니다.
### 순서 정하기 {/*taking-turns*/}
이제 이 틱택토 게임에서 가장 큰 결함인 "O"를 보드에 표시할 수 없다는 문제를 수정할 차례입니다.
-기본적으로 첫 번째 이동을 "X"로 설정합니다. 이제 보드 컴포넌트에 또 다른 state를 추가하여 추적해 보겠습니다.
+기본적으로 첫 번째 이동을 "X"로 설정합니다. 이제 보드 컴포넌트에 또 다른 State를 추가하여 추적해 보겠습니다.
```js {2}
function Board() {
@@ -1378,7 +1378,7 @@ function Board() {
}
```
-플레이어가 움직일 때마다 다음 플레이어를 결정하기 위해 불리언 값인 `xIsNext`가 반전되고 게임의 state가 저장됩니다. `Board`의 `handleClick` 함수를 업데이트하여 `xIsNext`의 값을 반전시키세요.
+플레이어가 움직일 때마다 다음 플레이어를 결정하기 위해 불리언 값인 `xIsNext`가 반전되고 게임의 State가 저장됩니다. `Board`의 `handleClick` 함수를 업데이트하여 `xIsNext`의 값을 반전시키세요.
```js {7,8,9,10,11,13}
export default function Board() {
@@ -1410,7 +1410,7 @@ export default function Board() {
`O`가 `X`를 덮어씌웁니다! 이렇게 하면 게임이 좀 더 흥미로워질 수 있지만 지금은 원래의 규칙을 유지하겠습니다.
-지금은 `X`와 `O`로 사각형을 표시할 때 먼저 해당 사각형에 이미 `X` 또는 `O`값이 있는지 확인하고 있지 않습니다. *일찍이 돌아와서* 이 문제를 해결하기 위해 사각형에 이미 `X`와 `O`가 있는지 확인하겠습니다. 사각형이 이미 채워져 있는 경우 보드의 state를 업데이트하기 전에 `handleClick` 함수에서 조기에 `return` 하겠습니다.
+지금은 `X`와 `O`로 사각형을 표시할 때 먼저 해당 사각형에 이미 `X` 또는 `O`값이 있는지 확인하고 있지 않습니다. *일찍이 돌아와서* 이 문제를 해결하기 위해 사각형에 이미 `X`와 `O`가 있는지 확인하겠습니다. 사각형이 이미 채워져 있는 경우 보드의 State를 업데이트하기 전에 `handleClick` 함수에서 조기에 `return` 하겠습니다.
```js {2,3,4}
function handleClick(i) {
@@ -1572,7 +1572,7 @@ function handleClick(i) {
}
```
-게임이 끝났을 때 플레이어에게 알리기 위해 "Winner: X" 또는 "Winner: O"라고 표시하겠습니다. 이렇게 하려면 `Board` 컴포넌트에 `status` 구역을 추가하면 됩니다. 게임이 끝나면 status는 승자를 표시하고 게임이 진행 중인 경우 다음 플레이어의 차례를 표시합니다.
+게임이 끝났을 때 플레이어에게 알리기 위해 "Winner: X" 또는 "Winner: O"라고 표시하겠습니다. 이렇게 하려면 `Board` 컴포넌트에 `status` 구역을 추가하면 됩니다. 게임이 끝나면 `status`는 승자를 표시하고 게임이 진행 중인 경우 다음 플레이어의 차례를 표시합니다.
```js {3-9,13}
export default function Board() {
@@ -1594,7 +1594,7 @@ export default function Board() {
}
```
-축하합니다! 이제 제대로 작동하는 틱택토 게임을 만들었습니다. 그리고 방금 React의 기본도 배웠습니다. 그러니 여기서 진정한 승자는 바로 _여러분_ 입니다. 코드는 다음과 같습니다.
+축하합니다! 이제 제대로 작동하는 틱택토 게임을 만들었습니다. 그리고 방금 React의 기본도 배웠습니다. 그러니 여기서 진정한 승자는 바로 여러분입니다. 코드는 다음과 같습니다.
@@ -1735,7 +1735,7 @@ body {
하지만 우리는 `slice()`를 사용하여 매번 이동할 때마다 `squares` 배열의 새 복사본을 만들고 이를 불변으로 처리했습니다. 덕분에 `squares` 배열의 모든 과거 버전을 저장할 수 있고 이미 발생한 턴 사이를 탐색할 수 있습니다.
-과거의 `squares` 배열을 `history`라는 다른 배열에 저장하고 이 배열을 새로운 state 변수로 저장하겠습니다. `history` 배열은 첫 번째 이동부터 마지막 이동까지 모든 보드 state를 나타내며 다음과 같은 모양을 갖습니다.
+과거의 `squares` 배열을 `history`라는 다른 배열에 저장하고 이 배열을 새로운 State 변수로 저장하겠습니다. `history` 배열은 첫 번째 이동부터 마지막 이동까지 모든 보드 State를 나타내며 다음과 같은 모양을 갖습니다.
```jsx
[
@@ -1749,11 +1749,11 @@ body {
]
```
-### 한 번 더 state 끌어올리기 {/*lifting-state-up-again*/}
+### 한 번 더 State 끌어올리기 {/*lifting-state-up-again*/}
-이제 과거 이동 목록을 표시하기 위해 새로운 최상위 컴포넌트 `Game`을 작성하세요. 여기에 전체 게임 기록을 포함하는 `history` state를 배치하겠습니다.
+이제 과거 이동 목록을 표시하기 위해 새로운 최상위 컴포넌트 `Game`을 작성하세요. 여기에 전체 게임 기록을 포함하는 `history` State를 배치하겠습니다.
-`history` state를 `Game` 컴포넌트에 배치하면 자식 `Board` 컴포넌트에서 `squares` state를 제거할 수 있습니다. `Square` 컴포넌트에서 `Board` 컴포넌트로 state를 "끌어올렸던" 것처럼, 이제 `Board` 컴포넌트에서 최상위 `Game` 컴포넌트로 state를 끌어올릴 수 있습니다. 이렇게 하면 `Game` 컴포넌트가 `Board` 컴포넌트의 데이터를 완전히 제어하고 `Board`의 `history`에서 이전 순서를 렌더링하도록 지시할 수 있습니다.
+`history` State를 `Game` 컴포넌트에 배치하면 자식 `Board` 컴포넌트에서 `squares` State를 제거할 수 있습니다. `Square` 컴포넌트에서 `Board` 컴포넌트로 State를 "끌어올렸던" 것처럼, 이제 `Board` 컴포넌트에서 최상위 `Game` 컴포넌트로 State를 끌어올릴 수 있습니다. 이렇게 하면 `Game` 컴포넌트가 `Board` 컴포넌트의 데이터를 완전히 제어하고 `Board`의 `history`에서 이전 순서를 렌더링하도록 지시할 수 있습니다.
먼저 `export default`가 있는 `Game` 컴포넌트를 추가하세요. 일부 마크업 안에 `Board` 컴포넌트를 렌더링하도록 하세요.
@@ -1776,9 +1776,9 @@ export default function Game() {
}
```
-`export default` 키워드를 `function Board() {` 선언 앞에서 제거하고 `function Game() {` 선언 앞에 추가한 것에 유의하세요. 이것은 `index.js` 파일에서 `Board` 컴포넌트 대신 `Game` 컴포넌트를 최상위 컴포넌트로 사용하도록 지시합니다. `Game` 컴포넌트가 반환하는 내용에 추가한 div는 나중에 보드에 추가할 게임 정보를 위한 공간을 확보합니다.
+`export default` 키워드를 `function Board() {` 선언 앞에서 제거하고 `function Game() {` 선언 앞에 추가한 것에 유의하세요. 이것은 `index.js` 파일에서 `Board` 컴포넌트 대신 `Game` 컴포넌트를 최상위 컴포넌트로 사용하도록 지시합니다. `Game` 컴포넌트가 반환하는 내용에 추가한 `div`는 나중에 보드에 추가할 게임 정보를 위한 공간을 확보합니다.
-다음 플레이어와 이동 기록을 추적하기 위해 `Game` 컴포넌트에 몇개의 state를 추가하세요.
+다음 플레이어와 이동 기록을 추적하기 위해 `Game` 컴포넌트에 몇개의 State를 추가하세요.
```js {2-3}
export default function Game() {
@@ -1799,7 +1799,7 @@ export default function Game() {
// ...
```
-다음으로 `Game` 컴포넌트 안에 `Board` 컴포넌트가 게임을 업데이트할 때 호출할 `handlePlay` 함수를 만드세요. `xIsNext` , `currentSquares` , `handlePlay` 를 `Board` 컴포넌트에 props로 전달하세요.
+다음으로 `Game` 컴포넌트 안에 `Board` 컴포넌트가 게임을 업데이트할 때 호출할 `handlePlay` 함수를 만드세요. `xIsNext` , `currentSquares` , `handlePlay`를 `Board` 컴포넌트에 Props로 전달하세요.
```js {6-8,13}
export default function Game() {
@@ -1820,7 +1820,7 @@ export default function Game() {
}
```
-`Board` 컴포넌트가 props에 의해 완전히 제어되도록 만들겠습니다. `Board` 컴포넌트를 `xIsNext`, `squares`, 그리고 플레이어가 움직일 때마다 `Board`가 업데이트된 사각형을 배열로 호출할 수 있는 새로운 `onPlay` 함수를 props로 받도록 변경하세요. 다음으로 `Board` 함수에서 `useState`를 호출하는 처음 두 줄을 제거하세요.
+`Board` 컴포넌트가 Props에 의해 완전히 제어되도록 만들겠습니다. `Board` 컴포넌트를 `xIsNext`, `squares`, 그리고 플레이어가 움직일 때마다 `Board`가 업데이트된 사각형을 배열로 호출할 수 있는 새로운 `onPlay` 함수를 Props로 받도록 변경하세요. 다음으로 `Board` 함수에서 `useState`를 호출하는 처음 두 줄을 제거하세요.
```js {1}
function Board({ xIsNext, squares, onPlay }) {
@@ -1851,11 +1851,11 @@ function Board({ xIsNext, squares, onPlay }) {
}
```
-`Board` 컴포넌트는 `Game` 컴포넌트가 전달한 props에 의해 완전히 제어됩니다. 게임이 다시 작동하게 하려면 `Game` 컴포넌트에서 `handlePlay` 함수를 구현해야 합니다.
+`Board` 컴포넌트는 `Game` 컴포넌트가 전달한 Props에 의해 완전히 제어됩니다. 게임이 다시 작동하게 하려면 `Game` 컴포넌트에서 `handlePlay` 함수를 구현해야 합니다.
`handlePlay`가 호출되면 무엇을 해야 할까요? 이전의 보드는 업데이트된 `setSquares`를 호출했지만, 이제는 업데이트된 `squares` 배열을 `onPlay`로 전달한다는 걸 기억하세요.
-`handlePlay` 함수는 리렌더링을 트리거하기 위해 `Game`의 state를 업데이트해야 하지만, 더 이상 호출할 수 있는 `setSquares` 함수가 없으며 대신 이 정보를 저장하기 위해 `history` state 변수를 사용하고 있습니다. 업데이트된 `squares` 배열을 새 히스토리 항목으로 추가하여 `history`를 업데이트해야 하고, Board에서 했던 것처럼 `xIsNext` 값을 반전시켜야 합니다.
+`handlePlay` 함수는 리렌더링을 트리거하기 위해 `Game`의 State를 업데이트해야 하지만, 더 이상 호출할 수 있는 `setSquares` 함수가 없으며 대신 이 정보를 저장하기 위해 `history` State 변수를 사용하고 있습니다. 업데이트된 `squares` 배열을 새 히스토리 항목으로 추가하여 `history`를 업데이트해야 하고, `Board`에서 했던 것처럼 `xIsNext` 값을 반전시켜야 합니다.
```js {4-5}
export default function Game() {
@@ -1868,11 +1868,11 @@ export default function Game() {
}
```
-위에서 `[...history, nextSquares]` 는 `history`에 있는 모든 항목을 포함하는 새 배열을 만들고 그 뒤에 `nextSquares`를 만듭니다. (`...history` [*전개 구문*](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax)을 "`history` 의 모든 항목 열거"로 읽을 수 있습니다)
+위에서 `[...history, nextSquares]`는 `history`에 있는 모든 항목을 포함하는 새 배열을 만들고 그 뒤에 `nextSquares`를 만듭니다. (`...history` [*전개 구문*](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax)을 "`history` 의 모든 항목 열거"로 읽을 수 있습니다.)
-예를 들어, `history`가 `[[null,null,null], ["X",null,null]]`이고 `nextSquares` 가 `["X",null,"O"]`라면 새로운 `[...history, nextSquares]` 배열은 `[[null,null,null], ["X",null,null], ["X",null,"O"]]`가 될 것입니다.
+예를 들어, `history`가 `[[null,null,null], ["X",null,null]]`이고 `nextSquares`가 `["X",null,"O"]`라면 새로운 `[...history, nextSquares]` 배열은 `[[null,null,null], ["X",null,null], ["X",null,"O"]]`가 될 것입니다.
-이 시점에서 state를 `Game` 컴포넌트로 옮겼으므로 리팩토링 전과 마찬가지로 UI가 완전히 작동해야 합니다. 이 시점에서 코드의 모습은 다음과 같습니다.
+이 시점에서 State를 `Game` 컴포넌트로 옮겼으므로 리팩토링 전과 마찬가지로 UI가 완전히 작동해야 합니다. 이 시점에서 코드의 모습은 다음과 같습니다.
@@ -2025,9 +2025,9 @@ body {
이제 틱택토 게임의 히스토리를 기록하므로, 플레이어에게 과거 이동 목록을 보여줄 수 있습니다.
-``과 같은 React 엘리먼트는 일반 JavaScript 객체이므로 애플리케이션에서 전달할 수 있습니다. React에서 여러 엘리먼트를 렌더링하려면 React 엘리먼트 배열을 사용할 수 있습니다.
+``과 같은 React 엘리먼트는 일반 자바스크립트 객체이므로 애플리케이션에서 전달할 수 있습니다. React에서 여러 엘리먼트를 렌더링하려면 React 엘리먼트 배열을 사용할 수 있습니다.
-이미 state에 이동 `history` 배열이 있으므로 이를 React 엘리먼트 배열로 변환해야 합니다. JavaScript에서 한 배열을 다른 배열로 변환하려면 [배열 `map` 메서드](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map)를 사용하면 됩니다.
+이미 State에 이동 `history` 배열이 있으므로 이를 React 엘리먼트 배열로 변환해야 합니다. 자바스크립트에서 한 배열을 다른 배열로 변환하려면 [배열 `map` 메서드](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map)를 사용하면 됩니다.
```jsx
[1, 2, 3].map((x) => x * 2) // [2, 4, 6]
@@ -2253,13 +2253,13 @@ body {
`map`으로 `history` 배열을 반복할 때 전달한 함수 내에서 `squares` 인수는 `history`의 각 엘리먼트를 통과하고, `move` 인수는 각 배열 인덱스를 통과합니다: `0`, `1`, `2`, … (대부분은 실제 배열 엘리먼트가 필요하지만, 이 경우에는 이동 목록을 렌더링하기 위해 인덱스만 있어도 됩니다.)
-틱택토 게임 history의 각 이동에 대해 버튼 ``이 포함된 목록 항목 `
`를 생성하세요. 버튼에는 (아직 구현하지 않은) `jumpTo`라는 함수를 호출하는 `onClick` 핸들러가 있습니다.
+틱택토 게임 `history`의 각 이동에 대해 버튼 ``이 포함된 목록 항목 `
`를 생성하세요. 버튼에는 (아직 구현하지 않은) `jumpTo`라는 함수를 호출하는 `onClick` 핸들러가 있습니다.
현재로서는 개발자 도구 콘솔에 게임의 발생한 동작 목록과 오류가 표시되어야 합니다. "key" 오류가 무엇을 의미하는지 알아보겠습니다.
### Key 선택하기 {/*picking-a-key*/}
-리스트를 렌더링할 때 React는 렌더링 된 각 리스트 항목에 대한 몇 가지 정보를 저장합니다. 리스트를 업데이트할 때 React는 무엇이 변경되었는지 확인해야 합니다. 리스트의 항목은 추가, 제거, 재정렬 또는 업데이트될 수 있습니다.
+리스트를 렌더링할 때 React는 렌더링된 각 리스트 항목에 대한 몇 가지 정보를 저장합니다. 리스트를 업데이트할 때 React는 무엇이 변경되었는지 확인해야 합니다. 리스트의 항목은 추가, 제거, 재정렬 또는 업데이트될 수 있습니다.
아래의 리스트가
@@ -2276,7 +2276,7 @@ body {
Alexa: 5 tasks left
```
-아마 task의 개수가 업데이트 되었을 뿐만 아니라 Alexa와 Ben의 순서가 바뀌고 Claudia가 두 사람 사이에 추가되었다고 생각할 것입니다. 그러나 React는 컴퓨터 프로그램이므로 우리가 의도한 바가 무엇인지 알지 못합니다. 그러므로 리스트의 항목에 _key_ 프로퍼티를 지정하여 각 리스트의 항목이 다른 항목과 다르다는 것을 구별해 주어야 합니다. 만약 데이터베이스에서 데이터를 불러와서 사용한다면 Alexa, Ben, Claudia의 데이터베이스 ID를 key로 사용할 수 있습니다.
+아마 task의 개수가 업데이트 되었을 뿐만 아니라 Alexa와 Ben의 순서가 바뀌고 Claudia가 두 사람 사이에 추가되었다고 생각할 것입니다. 그러나 React는 컴퓨터 프로그램이므로 우리가 의도한 바가 무엇인지 알지 못합니다. 그러므로 리스트의 항목에 _`key`_ 프로퍼티를 지정하여 각 리스트의 항목이 다른 항목과 다르다는 것을 구별해 주어야 합니다. 만약 데이터베이스에서 데이터를 불러와서 사용한다면 Alexa, Ben, Claudia의 데이터베이스 ID를 `key`로 사용할 수 있습니다.
```js {1}
@@ -2284,23 +2284,23 @@ body {
```
-리스트가 다시 렌더링 되면 React는 각 리스트 항목의 key를 가져와서 이전 리스트의 항목에서 일치하는 key를 탐색합니다. 현재 리스트에서 이전에 존재하지 않았던 key가 있으면 React는 컴포넌트를 생성합니다. 만약 현재 리스트에 이전 리스트에 존재했던 key를 가지고 있지 않다면 React는 그 key를 가진 컴포넌트를 제거합니다. 두 key가 일치한다면 해당 컴포넌트는 이동합니다.
+리스트가 다시 렌더링 되면 React는 각 리스트 항목의 `key`를 가져와서 이전 리스트의 항목에서 일치하는 `key`를 탐색합니다. 현재 리스트에서 이전에 존재하지 않았던 `key`가 있으면 React는 컴포넌트를 생성합니다. 만약 현재 리스트에 이전 리스트에 존재했던 `key`를 가지고 있지 않다면 React는 그 `key`를 가진 컴포넌트를 제거합니다. 두 `key`가 일치한다면 해당 컴포넌트는 이동합니다.
-key는 각 React가 각 컴포넌트를 구별할 수 있도록 하여 컴포넌트가 다시 렌더링 될 때 React가 해당 컴포넌트의 state를 유지할 수 있게 합니다. 컴포넌트의 key가 변하면 컴포넌트는 제거되고 새로운 state와 함께 다시 생성됩니다.
+`key`는 React가 각 컴포넌트를 구별할 수 있도록 하여 컴포넌트가 다시 렌더링 될 때 React가 해당 컴포넌트의 State를 유지할 수 있게 합니다. 컴포넌트의 `key`가 변하면 컴포넌트는 제거되고 새로운 State와 함께 다시 생성됩니다.
-`key`는 React에서 특별하고 미리 지정된 프로퍼티입니다. 엘리먼트가 생성되면 React는 `key` 프로퍼티를 추출하여 반환되는 엘리먼트에 직접 key를 저장합니다. `key`가 props로 전달되는 것처럼 보일 수 있지만, React는 자동으로 `key`를 사용해 업데이트할 컴포넌트를 결정합니다. 부모가 지정한 `key`가 무엇인지 컴포넌트는 알 수 없습니다.
+`key`는 React에서 특별하고 미리 지정된 프로퍼티입니다. 엘리먼트가 생성되면 React는 `key` 프로퍼티를 추출하여 반환되는 엘리먼트에 직접 `key`를 저장합니다. `key`가 Props로 전달되는 것처럼 보일 수 있지만, React는 자동으로 `key`를 사용해 업데이트할 컴포넌트를 결정합니다. 부모가 지정한 `key`가 무엇인지 컴포넌트는 알 수 없습니다.
-**동적인 리스트를 만들 때마다 적절한 key를 할당하는 것을 강력하게 추천합니다.** 적절한 key가 없는 경우 데이터를 재구성하는 것을 고려해 보세요.
+**동적인 리스트를 만들 때마다 적절한 `key`를 할당하는 것을 강력하게 추천합니다.** 적절한 `key`가 없는 경우 데이터를 재구성하는 것을 고려해 보세요.
-key가 지정되지 않은 경우, React는 경고를 표시하며 배열의 인덱스를 기본 key로 사용합니다. 배열 인덱스를 key로 사용하면 리스트 항목의 순서를 바꾸거나 항목을 추가/제거할 때 문제가 발생합니다. 명시적으로 `key={i}`를 전달하면 경고는 사라지지만 배열의 인덱스를 사용할 때와 같은 문제가 발생하므로 대부분은 추천하지 않습니다.
+`key`가 지정되지 않은 경우, React는 경고를 표시하며 배열의 인덱스를 기본 `key`로 사용합니다. 배열 인덱스를 `key`로 사용하면 리스트 항목의 순서를 바꾸거나 항목을 추가/제거할 때 문제가 발생합니다. 명시적으로 `key={i}`를 전달하면 경고는 사라지지만 배열의 인덱스를 사용할 때와 같은 문제가 발생하므로 대부분은 추천하지 않습니다.
-key는 전역적으로 고유할 필요는 없으며 컴포넌트와 해당 컴포넌트의 형제 컴포넌트 사이에서만 고유하면 됩니다.
+`key`는 전역적으로 고유할 필요는 없으며 컴포넌트와 해당 컴포넌트의 형제 컴포넌트 사이에서만 고유하면 됩니다.
### 시간여행 구현하기 {/*implementing-time-travel*/}
-틱택토 게임의 기록에서 과거의 각 이동에는 해당 이동의 일련번호인 고유 ID가 있습니다. 이동은 중간에 순서를 바꾸거나 삭제하거나 삽입할 수 없으므로 이동 인덱스를 key로 사용하는 것이 안전합니다.
+틱택토 게임의 기록에서 과거의 각 이동에는 해당 이동의 일련번호인 고유 ID가 있습니다. 이동은 중간에 순서를 바꾸거나 삭제하거나 삽입할 수 없으므로 이동 인덱스를 `key`로 사용하는 것이 안전합니다.
-`Game` 함수에서 `
`로 key를 추가할 수 있으며 렌더링 된 게임을 다시 로드하면 React의 "key" 에러가 사라질 것입니다.
+`Game` 함수에서 `
`로 `key`를 추가할 수 있으며 렌더링된 게임을 다시 로드하면 React의 "key" 에러가 사라질 것입니다.
```js {4}
const moves = history.map((squares, move) => {
@@ -2480,7 +2480,7 @@ body {
-`jumpTo`를 구현하기 전에 사용자가 현재 어떤 단계를 보고 있는지를 추적할 수 있는 `Game` 컴포넌트가 필요합니다. 이를 위해 기본값이 `0`인 `currentMove` 라는 새 state 변수를 정의하세요.
+`jumpTo`를 구현하기 전에 사용자가 현재 어떤 단계를 보고 있는지를 추적할 수 있는 `Game` 컴포넌트가 필요합니다. 이를 위해 기본값이 `0`인 `currentMove` 라는 새 State 변수를 정의하세요.
```js {4}
export default function Game() {
@@ -2707,9 +2707,9 @@ body {
코드를 자세히 살펴보면 `currentMove`가 짝수일 때는 `xIsNext === true`가 되고, `currentMove`가 홀수일 때는 `xIsNext === false`가 되는 것을 알 수 있습니다. 즉, `currentMove`의 값을 알고 있다면 언제나 `xIsNext`가 무엇인지 알아낼 수 있습니다.
-이 두 가지 state를 모두 저장할 이유가 없습니다. 항상 중복되는 state는 피하세요. state에 저장하는 것을 단순화하면 버그를 줄이고 코드를 더 쉽게 이해할 수 있습니다. `Game`을 변경하여 더 이상 `xIsNext`를 별도의 state 변수로 저장하지 않고 `currentMove`를 기반으로 알아내도록 수정하겠습니다.
+이 두 가지 State를 모두 저장할 이유가 없습니다. 항상 중복되는 State는 피하세요. State에 저장하는 것을 단순화하면 버그를 줄이고 코드를 더 쉽게 이해할 수 있습니다. `Game`을 변경하여 더 이상 `xIsNext`를 별도의 State 변수로 저장하지 않고 `currentMove`를 기반으로 알아내도록 수정하겠습니다.
-```js {4,11,15}
+```js {4,10,14}
export default function Game() {
const [history, setHistory] = useState([Array(9).fill(null)]);
const [currentMove, setCurrentMove] = useState(0);
@@ -2729,7 +2729,7 @@ export default function Game() {
}
```
-더 이상 `xIsNext` state 선언이나 `setXIsNext` 호출이 필요하지 않습니다. 이제 컴포넌트를 코딩하는 동안 실수를 하더라도 `xIsNext`가 `currentMove`와 동기화되지 않을 가능성이 없습니다.
+더 이상 `xIsNext` State 선언이나 `setXIsNext` 호출이 필요하지 않습니다. 이제 컴포넌트를 코딩하는 동안 실수를 하더라도 `xIsNext`가 `currentMove`와 동기화되지 않을 가능성이 없습니다.
### 마무리 {/*wrapping-up*/}
@@ -2919,4 +2919,4 @@ body {
1. 누군가 승리하면 승리의 원인이 된 세 개의 사각형을 강조 표시해 보세요. (아무도 승리하지 않으면 무승부라는 메시지를 표시하세요. )
1. 이동 히스토리 목록에서 각 이동의 위치를 형식(열, 행)으로 표시해 보세요.
-이 자습서를 통해 엘리먼트, 컴포넌트, props, state를 포함한 React의 개념에 대해 살펴봤습니다. 이제 이러한 개념이 게임을 만들 때 어떻게 작동하는지 보았으니, [React로 사고하기](/learn/thinking-in-react)를 통해 앱의 UI를 만들 때 동일한 React 개념이 어떻게 작동하는지 확인해 보세요.
+이 자습서를 통해 엘리먼트, 컴포넌트, Props, State를 포함한 React의 개념에 대해 살펴봤습니다. 이제 이러한 개념이 게임을 만들 때 어떻게 작동하는지 보았으니, [React로 사고하기](/learn/thinking-in-react)를 통해 앱의 UI를 만들 때 동일한 React 개념이 어떻게 작동하는지 확인해 보세요.