v19.2Latest

React 방식으로 생각하기

React는 여러분이 바라보는 디자인과 구축하는 앱에 대한 생각을 바꿀 수 있습니다. React로 사용자 인터페이스를 구축할 때는 먼저 이를컴포넌트라는 조각들로 분해합니다. 그런 다음 각 컴포넌트의 다양한 시각적 상태를 설명합니다. 마지막으로 데이터가 컴포넌트들을 통해 흐르도록 컴포넌트들을 연결합니다. 이 튜토리얼에서는 React로 검색 가능한 제품 데이터 테이블을 구축하는 사고 과정을 안내합니다.

목업으로 시작하기

이미 JSON API와 디자이너로부터 받은 목업이 있다고 상상해 보세요.

JSON API는 다음과 같은 데이터를 반환합니다:

목업은 다음과 같습니다:

React에서 UI를 구현하려면 일반적으로 동일한 다섯 단계를 따릅니다.

1단계: UI를 컴포넌트 계층 구조로 분해하기

먼저 목업의 모든 컴포넌트와 하위 컴포넌트 주위에 상자를 그리고 이름을 지정하세요. 디자이너와 함께 작업한다면, 그들이 이미 디자인 도구에서 이러한 컴포넌트에 이름을 붙였을 수 있습니다. 물어보세요!

배경에 따라 디자인을 컴포넌트로 분할하는 방법을 다르게 생각할 수 있습니다:

  • 프로그래밍—새 함수나 객체를 생성해야 하는지 결정할 때 사용하는 기법과 동일합니다. 그 중 하나는관심사 분리입니다. 즉, 컴포넌트는 이상적으로 한 가지 일에만 관심을 가져야 합니다. 결국 커지게 되면 더 작은 하위 컴포넌트로 분해되어야 합니다.
  • CSS—어떤 클래스 선택자를 만들지 고려하세요. (하지만 컴포넌트는 조금 더 덜 세분화됩니다.)
  • 디자인—디자인의 레이어를 어떻게 구성할지 고려하세요.

JSON이 잘 구조화되어 있다면, 종종 UI의 컴포넌트 구조에 자연스럽게 매핑된다는 것을 발견할 것입니다. 이는 UI와 데이터 모델이 종종 동일한 정보 구조, 즉 동일한 형태를 가지기 때문입니다. UI를 컴포넌트로 분리하되, 각 컴포넌트가 데이터 모델의 한 부분과 일치하도록 하세요.

이 화면에는 다섯 개의 컴포넌트가 있습니다:

  1. FilterableProductTable(회색)은 전체 앱을 포함합니다.
  2. SearchBar(파란색)은 사용자 입력을 받습니다.
  3. ProductTable(라벤더색)은 사용자 입력에 따라 목록을 표시하고 필터링합니다.
  4. ProductCategoryRow(초록색)은 각 카테고리에 대한 제목을 표시합니다.
  5. ProductRow(노란색)은 각 제품에 대한 행을 표시합니다.

만약 ProductTable(라벤더색)을 보면, 테이블 헤더("Name" 및 "Price" 레이블을 포함하는)가 자체 컴포넌트가 아니라는 것을 알 수 있습니다. 이는 선호도의 문제이며, 어느 쪽으로든 갈 수 있습니다. 이 예제에서는ProductTable의 일부입니다. 왜냐하면ProductTable의 목록 안에 나타나기 때문입니다. 그러나 이 헤더가 복잡해지면(예: 정렬 기능 추가), 이를 자체ProductTableHeader컴포넌트로 이동할 수 있습니다.

이제 목업에서 컴포넌트를 식별했으니, 이를 계층 구조로 배열하세요. 목업에서 다른 컴포넌트 안에 나타나는 컴포넌트는 계층 구조에서 자식으로 나타나야 합니다:

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

2단계: React에서 정적 버전 구축하기

이제 컴포넌트 계층 구조가 있으니, 앱을 구현할 차례입니다. 가장 직관적인 접근 방식은 아직 상호작용성을 추가하지 않고 데이터 모델에서 UI를 렌더링하는 버전을 구축하는 것입니다. 종종 정적 버전을 먼저 구축하고 나중에 상호작용성을 추가하는 것이 더 쉽습니다. 정적 버전을 구축하는 것은 많은 타이핑이 필요하고 생각할 필요가 없지만, 상호작용성을 추가하는 것은 많은 생각이 필요하고 타이핑은 많지 않습니다.

데이터 모델을 렌더링하는 앱의 정적 버전을 구축하려면, 다른 컴포넌트를 재사용하고컴포넌트를 구축하고 props를 사용하여 데이터를 전달하는 상태개념에 익숙하다면, 이 정적 버전을 구축할 때 상태를 전혀 사용하지 마세요. 상태는 상호작용성, 즉 시간이 지남에 따라 변경되는 데이터를 위해 예약되어 있습니다. 이는 앱의 정적 버전이므로 필요하지 않습니다.)

계층 구조에서 상위에 있는 컴포넌트(예: FilterableProductTable)를 먼저 구축하는 "상향식" 접근법이나 하위에 있는 컴포넌트(예:ProductRow)부터 작업하는 "하향식" 접근법을 사용할 수 있습니다. 더 간단한 예제에서는 일반적으로 상향식이 더 쉽고, 더 큰 프로젝트에서는 하향식이 더 쉽습니다.

(이 코드가 어려워 보인다면, 먼저빠른 시작을 살펴보세요!)

컴포넌트를 구축한 후에는 데이터 모델을 렌더링하는 재사용 가능한 컴포넌트 라이브러리를 갖게 됩니다. 이는 정적 앱이므로 컴포넌트는 JSX만 반환합니다. 계층 구조의 최상위 컴포넌트(FilterableProductTable)는 데이터 모델을 prop으로 받습니다. 이를단방향 데이터 흐름이라고 합니다. 데이터가 최상위 컴포넌트에서 트리 하단의 컴포넌트로 흐르기 때문입니다.

주의사항

이 시점에서는 아직 상태 값을 사용해서는 안 됩니다. 그것은 다음 단계에서 할 일입니다!

3단계: UI 상태의 최소이면서 완전한 표현 찾기

UI를 상호작용적으로 만들려면 사용자가 기본 데이터 모델을 변경할 수 있도록 해야 합니다. 이를 위해상태를 사용하게 됩니다.

상태를 앱이 기억해야 하는 변경 가능한 데이터의 최소 집합으로 생각하세요. 상태를 구조화하는 가장 중요한 원칙은DRY(반복하지 마세요) 원칙을 따르는 것입니다. 애플리케이션이 필요로 하는 상태의 절대적인 최소 표현을 찾아내고, 그 외 모든 것은 필요할 때 계산하세요. 예를 들어, 쇼핑 목록을 만드는 경우 항목들을 상태에 배열로 저장할 수 있습니다. 목록의 항목 수도 표시하고 싶다면, 항목 수를 또 다른 상태 값으로 저장하지 말고 배열의 길이를 읽으세요.

이제 이 예제 애플리케이션의 모든 데이터 조각을 생각해 보세요:

  1. 원본 제품 목록
  2. 사용자가 입력한 검색어
  3. 체크박스의 값
  4. 필터링된 제품 목록

이 중 어떤 것이 상태일까요? 상태가 아닌 것을 식별하세요:

  • 시간이 지나도변하지 않나요? 그렇다면 상태가 아닙니다.
  • 부모로부터 props로전달받나요? 그렇다면 상태가 아닙니다.
  • 기존 상태나 props를 기반으로 계산할 수 있나요? 그렇다면 그것은 확실히상태가 아닙니다!

남은 것이 아마 상태일 것입니다.

다시 하나씩 살펴보겠습니다:

  1. 원본 제품 목록은 props로 전달되므로 상태가 아닙니다.
  2. 검색어는 시간이 지남에 따라 변하고 다른 것으로부터 계산할 수 없으므로 상태로 보입니다.
  3. 체크박스의 값은 시간이 지남에 따라 변하고 다른 것으로부터 계산할 수 없으므로 상태로 보입니다.
  4. 필터링된 제품 목록은원본 제품 목록을 가져와 검색어와 체크박스 값에 따라 필터링하여 계산할 수 있으므로 상태가 아닙니다.

즉, 검색어와 체크박스의 값만이 상태라는 뜻입니다! 잘하셨습니다!

Deep Dive
Props vs State

4단계: state가 위치해야 할 곳 식별하기

앱의 최소한의 state 데이터를 식별한 후에는, 어떤 컴포넌트가 이 state를 변경하거나 state를소유하는지식별해야 합니다. 기억하세요: React는 단방향 데이터 흐름을 사용하여 데이터를 부모 컴포넌트에서 자식 컴포넌트로 계층 구조를 따라 아래로 전달합니다. 어떤 컴포넌트가 어떤 state를 소유해야 하는지 즉시 명확하지 않을 수 있습니다. 이 개념이 처음이라면 어려울 수 있지만, 다음 단계를 따라가면 알아낼 수 있습니다!

애플리케이션의 각 state 조각에 대해:

  1. 해당 state를 기반으로 무언가를 렌더링하는모든 컴포넌트를 식별합니다.
  2. 계층 구조에서 그들 모두 위에 있는 컴포넌트인 가장 가까운 공통 부모 컴포넌트를 찾습니다.
  3. state가 위치해야 할 곳을 결정합니다:
    1. 종종 state를 공통 부모에 직접 넣을 수 있습니다.
    2. state를 공통 부모 위의 어떤 컴포넌트에 넣을 수도 있습니다.
    3. state를 소유하는 것이 합리적인 컴포넌트를 찾을 수 없다면, state를 보관하기 위한 새로운 컴포넌트를 생성하고 공통 부모 컴포넌트 위의 계층 구조 어딘가에 추가하세요.

이전 단계에서 이 애플리케이션의 두 가지 state 조각을 찾았습니다: 검색 입력 텍스트와 체크박스의 값입니다. 이 예시에서는 항상 함께 나타나므로, 이들을 같은 곳에 두는 것이 합리적입니다.

이제 이들을 위한 전략을 따라가 봅시다:

  1. state를 사용하는 컴포넌트 식별:
    • ProductTable은 해당 state(검색 텍스트 및 체크박스 값)를 기반으로 제품 목록을 필터링해야 합니다.
    • SearchBar은 해당 state(검색 텍스트 및 체크박스 값)를 표시해야 합니다.
  2. 공통 부모 찾기:두 컴포넌트가 공유하는 첫 번째 부모 컴포넌트는FilterableProductTable입니다.
  3. state가 위치할 곳 결정: 필터 텍스트와 체크된 상태 값을FilterableProductTable에 보관하겠습니다.

따라서 state 값은FilterableProductTable에 위치하게 됩니다.

컴포넌트에 state를 추가하려면useState() Hook을 사용하세요.Hook은 React에 "연결"할 수 있게 해주는 특별한 함수입니다.FilterableProductTable상단에 두 개의 state 변수를 추가하고 초기 상태를 지정하세요:

그런 다음,filterTextinStockOnlyProductTableSearchBar에 props로 전달하세요:

이제 애플리케이션이 어떻게 동작할지 확인할 수 있습니다. 아래 샌드박스 코드에서filterText의 초기값을useState('')에서useState('fruit')로 편집해 보세요. 검색 입력 텍스트와 테이블이 모두 업데이트되는 것을 볼 수 있습니다:

폼을 편집해도 아직 작동하지 않습니다. 위 샌드박스의 콘솔 오류가 그 이유를 설명합니다:

콘솔

`onChange` 핸들러 없이 폼 필드에 `value` prop을 제공했습니다. 이는 읽기 전용 필드를 렌더링합니다.

위 샌드박스에서ProductTableSearchBarfilterTextinStockOnlyprops를 읽어 테이블, 입력창, 체크박스를 렌더링합니다. 예를 들어,SearchBar가 입력값을 채우는 방법은 다음과 같습니다:

하지만 아직 사용자 입력(예: 타이핑)에 반응하는 코드를 추가하지 않았습니다. 이것이 마지막 단계가 될 것입니다.

5단계: 역방향 데이터 흐름 추가

현재 앱은 props와 state가 계층 구조를 따라 아래로 흐르면서 올바르게 렌더링됩니다. 하지만 사용자 입력에 따라 state를 변경하려면 반대 방향의 데이터 흐름을 지원해야 합니다: 계층 구조 깊숙이 있는 폼 컴포넌트가FilterableProductTable의 state를 업데이트해야 합니다.

React는 이 데이터 흐름을 명시적으로 만들지만, 양방향 데이터 바인딩보다 약간 더 많은 타이핑이 필요합니다. 위 예제에서 입력창에 타이핑하거나 체크박스를 선택해 보면 React가 입력을 무시하는 것을 볼 수 있습니다. 이것은 의도된 것입니다.<input value={filterText} />를 작성함으로써,inputvalue prop을 항상 FilterableProductTable에서 전달된 filterTextstate와 같도록 설정했습니다.filterTextstate가 설정되지 않았기 때문에 입력창은 절대 변하지 않습니다.

사용자가 폼 입력을 변경할 때마다 state가 해당 변경 사항을 반영하도록 업데이트되도록 만들고 싶습니다. state는FilterableProductTable가 소유하므로, 오직 그것만이setFilterTextsetInStockOnly를 호출할 수 있습니다.SearchBarFilterableProductTable의 state를 업데이트할 수 있도록 하려면, 이 함수들을SearchBar로 전달해야 합니다:

이제 SearchBar 내부에서 onChange이벤트 핸들러를 추가하고 그 안에서 부모 state를 설정합니다:

이제 애플리케이션이 완전히 작동합니다!

이벤트 처리 및 상태 업데이트에 관한 모든 내용은상호작용 추가하기섹션에서 배울 수 있습니다.

다음 단계

이는 React로 컴포넌트와 애플리케이션을 구축하는 방법에 대한 매우 간략한 소개였습니다. 지금 바로React 프로젝트를 시작하거나 이 튜토리얼에서 사용된모든 구문을 더 깊이 파고들어볼 수 있습니다.