UI 구현을 모두 마쳤으므로 이 UI 요소들을 움직이게 하는 카운터 기능들을 차례로
구현하겠습니다.
State를 이용해 카운터 기능 구현하기
여러분이 구현할 카운터의 기능을 한 문장으로 정의하면 다음과 같습니다.
“Controller 컴포넌트에 있는 버튼을 클릭하면, Viewer 컴포넌트에 있는 카운트 가 증가하거나 감소해야 한다.”
예를 들어 Controller 컴포넌트에 있는 <+100> 버튼을 클릭하면 Viewer 컴포넌 트의 숫자는 0에서 100으로 바뀌어야 합니다.

버튼 클릭 이벤트가 발생했을 때 컴포넌트 값을 동적으로 렌더링하려면 리액트의
State를 사용해야 합니다. 그렇다면 [카운터] 앱에서 State를 사용해 어떻게 컴포넌트의 값을 동적으로 렌더링하는지 그 과정을 간단히 설명해 보겠습니다.
바로 실습을 진행할 수도 있지만 이 과정을 머릿속에서 그려보는 게 훨씬 도움을 줍니다.
먼저 카운트를 관리할 State를 만들고 초깃값을 0으로 설정합니다.
다음으로 Controller 컴포넌트의 버튼을 클릭하면 현재 State 값을 버튼이 전달하는 값과 계산해 변경합니다. 다음으로 변경된 State 값은 Viewer 컴포넌트에 전달되어 페이지의 카운트 값을 업데이트합니다.
다음은 이 과정을 알기 쉽게 도해화한 그림입니다.

다음 과정에서 중요한 점을 하나 짚어보고 가겠습니다.
앱을 설계하는 데 꼭 필요한 사고 실험 같은 겁니다.
State는 어떤 컴포넌트에 만들까?
State는 반드시 컴포넌트 함수 안에 만들어야 합니다. 현재 여러분과 함께 만들고 있는 [카운터] 앱에는 App, Viewer, Controller 3개의 컴포넌트가 있습니다. 그렇다 면 어떤 컴포넌트에서 [카운터] 앱의 State를 만들어야 할까요?
정답은 App 컴포넌트입니다.
왜 그럴까요? 정답인 이유를 확실히 아는 좋은 방법은 오답을 선택해 보고 무엇 이 문제인지 직접 느껴보는 겁니다.
Viewer 또는 Controller 컴포넌트에 State를 만들고 이 State를 이용해 카운트 기능을 구현하면 어떤 문제가 생기는지 살펴보겠습니다.
오답 1: Viewer 컴포넌트
Viewer 컴포넌트에서 [카운터] 앱에 사용할 State를 만듭니다. Viewer.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...① useState를 이용해 State 변수 count를 만듭니다. ② count 값을 페이지에 렌더링합니다.
Viewer 컴포넌트에서 State를 만들고 값을 렌더링하였습니다.
이제 Controller 컴포넌트에서 버튼을 클릭하면 set 함수인 setCount를 호출해야 합니다. 그런데 여기서 문제가 있습니다.
Viewer 컴포넌트가 Controller 컴포넌트에 setCount를 전달할 방법이 없다는 겁니다. 5장에서 살펴보았듯이 리액트에서 컴포넌트가 다른 컴포넌트에 데이터를 전달할 때는 Props를 사용하는데, Props는 부모만이 자식에게 전달할 수 있습니다. Viewer와 Controller 컴포넌트는 부모-자식 관계가 아니므로 어떠한 값도 전달할 수 없습니다.

오답 2: Controller 컴포넌트
이번에는 Controller 컴포넌트에 [카운터] 앱에 사용할 State를 만듭니다. Controller.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...① 버튼에서 클릭 이벤트가 발생하면 호출되는 이벤트 핸들러handleSetCount를 만듭니다. 이 함수에서는 set 함수 setCount를 호출하는데, 인수로 현재 State(count) 값과 매개변수 value 값을 더해 전달합니다. ②~⑦ 6개의 버튼은 모두 클릭 이벤트가 발생하면 이벤트 핸들러 handleSetCount를 호출합니다. 해당 버튼의 숫자를 인수로 전달합니다.
버튼을 클릭하면 State는 기존 값에서 해당 버튼의 숫자와 계산한 값으로 변경됩니다. 그러나 여기서도 문제가 있습니다. 변경된 State 값을 Viewer 컴포넌트에 전달할 방법이 없기 때문입니다.
다시 말해 State 변수 count를 Viewer 컴포넌트에 전달해야 하는데, Viewer와 Controller컴포넌트는 부모-자식 관계가 아니므로 그렇게 할 수 없습니다.

정답: App 컴포넌트
Viewer, Controller 모두 [카운터] 앱의 State가 있을 컴포넌트가 아니라는 것을 확인했습니다. 이번에는 정답인 App 컴포넌트에서 State를 만들고 카운트 기능을 완성하겠습니다.
App.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...① Viewer 컴포넌트에 State 변수 count의 값을 Props로 전달합니다 ② Controller 컴포넌트에 State 값을 변경하는 함수 setCount를 Props로 전달합니다
다음에는 Viewer 컴포넌트에서 App에서 받은 Props를 페이지에 렌더링합니다.
코드를 불러오는 중 입니다 ...App 컴포넌트에서 받은 Props를 페이지에 렌더링합니다. 5장에서 살펴보았듯이 리액트에서는 부모가 리렌더되거나 전달된 Props가 변경되면 자식 컴포넌트도 자동으로 리렌더됩니다.
따라서 Viewer 컴포넌트는 Props로 받은 State 값이 변경될 때 마다 리렌더되어 실시간으로 이 값을 페이지에 렌더링합니다.
다음으로 Controller.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...App 컴포넌트에서 함수 handleSetCount를 받아 버튼의 이벤트 핸들러로 사용합니다. 버튼을 클릭하면 함수 handleSetCount를 호출하는데, 이 함수는 App 컴포넌트의 State 값을 업데이트합니다.
저장하고 카운트 기능이 잘 구현되는지 확인합니다
![[카운터] 앱의 최종 구현](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Ff886b568-2100-4c8f-9415-7e0216de075b%2FUntitled.png?table=block&id=6884d54b-be37-4782-9dda-aafc518d3937&cache=v2)
지금까지 카운트 기능을 구현하려면 State를 App 컴포넌트에서 만들어야 한다는 점을 살펴보았습니다. 그 이유를 다시 정리하면 State 값은 Viewer 컴포넌트, set 함수는 Controller 컴포넌트에 전달해야 하기 때문입니다.
리액트는 State 값이나 set함수를 여러 컴포넌트에서 사용하는 경우, 이들을 상위 컴포넌트에서 관리합니다. 리액트에서는 이 기능을 다른 말로 ‘State 끌어올리기(State Lifting)’라고 합니다.
리액트답게 설계하기
리액트는 규모가 크고 빠른 웹 애플리케이션을 만들기 좋은 기술입니다. 이를 위해 리액트가 권장하는 애플리케이션 설계 방식에 대해 살펴보겠습니다.
리액트에서 컴포넌트 간에 데이터를 전달할 때는 Props를 사용하는데, 전달 방향 은 언제나 부모로부터 자식에게 전달하는 방식입니다. 리액트의 이러한 데이터 전 달 특징을 ‘단방향 데이터 흐름’이라고 합니다.

데이터를 항상 아래로 전달하는 단방향 데이터 흐름은 모든 자동차가 같은 방향으로만 달리는 일방통행 차선을 연상하게 합니다. 모든 자동차가 한 방향으로만 달린다면, 초보 운전자 입장에서는 운전하기가 수월하며, 교통 상황도 한눈에 확인할 수 있어 편합니다.
리액트의 단방향 데이터 전달은 데이터의 흐름을 이해하기 쉽고, 관리하기 좋다는 장점이 있습니다.
반면 State를 변경하는 이벤트는 자식에서 부모를 향해 역방향으로 전달되어야
합니다.

이번에 만들어본 간단한 [카운터] 앱에서는 Controller 컴포넌트에 있는 버튼 요소
를 클릭할 때마다 App 컴포넌트의 State를 업데이트하는 이벤트가 발생합니다.
App 컴포넌트는 자신이 관리하는 State를 변경하는 함수를 Props로 전달해 자식이 부모의 State를 대신 업데이트하게 했습니다.
결론적으로 리액트 앱을 설계할 때는 데이터는 위에서 아래로, 이벤트는 아래에서 위로 향하도록 설계해야 합니다.
이번 장에서는 간단한 [카운터] 앱을 만드는 프로젝트를 진행했고 리액트답게 설
계하는 방법도 알아보았습니다. 이번 장에서 만든 [카운터] 앱은 앞으로도 계속 쓰
일 예정이니 삭제하지 않습니다.