IT

[영어로 배우는 React] 12. 리액트로 생각하기

생각파워 2022. 4. 28. 18:03

공식 사이트 : https://reactjs.org/docs/thinking-in-react.html

 

 

리액트는 우리생각에 가장 빠르고, 크게 웹앱을 개발할 수 있는 최상의 방법입니다. 페이스북과 인스타그램에서 우리를 위해 아주 잘 확장되었습니다. 

 

리액트의 많은 훌륭한 부분들 중 하나는 앱을 빌드할 때 앱을 생각하게 만드는 방법입니다. 이 문서에서 우리는 검색가능한 물품데이터 테이블을 만드는 절차를 생각해보면서 살펴볼 것입니다. 

 

임시 디자인으로 시작

생각해보세요. 우리가 이미 디자이너로부터 JSON API와 mock을 받았다고 말이죠. 임시 디자인은 다음과 같습니다. 

우리의 JSON API는 아래와 같은 데이터를 리턴합니다.

[
  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

 

1단계 : 컴포넌트 계층으로 UI를 분리하라

해야할 제일 첫번째 작업은 mock안의 모든 컴포넌트(서브 컴포넌트를 포함하여)를 박스로 두르고, 거기에 이름을 붙이는 것입니다. 만약 디자이너와 함께 작업한다면, 디자이너가 이 작업을 마쳤을 수 있습니다. 그들과 대화해 보세요. 디자이너의 포토샵 레이어 이름이 리액트 컴포넌트 이름으로 되어 있을지 모릅니다. 

 

그런데, 자신의 컴포넌트가 무엇인지 어떻게 알수 있을까요? 새함수와 객체를 생성해야되는지 결정할때 사용하는것과 같은 테크닉을 사용합니다. 한가지 테크닉은 단일 책임 원칙입니다. 이것은 컴포넌트는 이상적으로 하나의 일만을 해야한다는 원칙입니다. 만약 컴포넌트가 더 커진다면 작은 서브 컴포넌트로 분리해야 합니다. 

 

종종 JSON데이터 모델을 유저에게 보여줘야하기 때문에, 모델이 올바르게 만들어진 경우, UI 및 컴포넌트 구조가 멋지게 매핑된다는 것을 알게 될 것입니다. 그것이 UI와 데이터 모델이 같은 정보구조를 추종하는 경향이 있는 이유입니다. 각각의 컴포넌트가 데이터모델의 한 조각과 매칭되게 UI를 컴포넌트로 분리하세요.

우리는 여기서 UI가 다섯개의 컴포넌트로 이루어진 것을 볼 수 있습니다. 각 컴포넌트가 나타내는 데이터를 이탤릭체로 표시했습니다. 위 이미지의 숫자는 아래의 숫자와 대응됩니다. 

 

  1. FilterableProductTable(오랜지색) : 예제 전체를 포함
  2. SeachBar(파란색) : 모든 유저의 입력을 받음
  3. ProductTable(초록색) : 사용자 입력을 기초로 데이터를 필터하고 표시
  4. ProductCategoryRow(청록색) : 카테고리 제목 표시
  5. ProductRow(빨간색) : 상품 정보 한줄 표시

ProductTable을 보면, "Name"과 "Price"를 포함한 테이블 헤더가 컴포넌트가 아닌것을 볼 수 있습니다. 이것은 선호의 문제인데, 지금은 인자로 만들어진 방식입니다. 우리는 이 예에서 Name과 Price가 ProductTable컴포넌트가 책임져야하는 부분이기 때문에, ProductTable 컴포넌트의 일부분으로 남겨놨습니다. 그러나 이 헤더가 더 복잡해진다면, ProductTableHeader 컴포넌트로 만들어야 할것입니다. 

 

지금까지 우리의 mock에서 component를 추출했습니다. 이제 계층도로 정렬해보도록 하겠습니다. 자식 레코드는 계층의 아래에 나타납니다. 

 

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

 

2단계 : 리액트로 고정버전 만들기

2단계 결과물을 먼저 보겠습니다. Thinking In React: Step 2 

 

지금 우리는 컴포넌트 계층도를 가지고 있습니다. 이제 앱으로 구현할 때입니다. 데이터 모델을 가져오고, UI를 랜더링하지만 상호작용하지 않는 버전을 만드는 것이 가장 쉽습니다. 고정된 버전은 생각없이 많은 타이핑만을 필요로 하고, 상호작용을 추가하는 것은 많은 생각과 작은 타이핑을 요구하기 때문에, 이 방법이 프로세스들을 분리하는데 가장 최상의 방법입니다. 우리는 왜 그런지 살펴볼 것입니다. 

 

데이터 모델을 랜더링하는 앱의 static 버전을 만들기 위해, 다른 컴포넌트를 재사용하고, props를 이용해 데이터를 전달하는 컴포넌트를 만들기를 원할 것입니다. props는 부모에게서 자식으로 데이터를 전달하는 방법입니다. 만일 state 컨셉이 익숙하더라도 static 버전을 만들기 위해서 state를 사용해서는 안됩니다. state는 변경되는 데이터의 상호작용을에만 예약되어져 있습니다. 이앱은 static 버전이기 때문에 state를 사용할 필요가 없습니다. 

 

당신은 top-down 이나 bottom-up 방식으로 만들 수 있습니다. 그것은 컴포넌트를 계층도 상에서 상위 컴포넌트부터 만들거나 하위 컴포넌트 부터 만들 수 있습니다. 간단한 예에서는 top-down으로 하는 것이 더 쉽습니다. 큰 프로젝트에서는 bottom-up 으로 하는 것이 더 쉽고, 만들면서 테스트를 생성할 수 있습니다. 

 

이 스템의 끝에서, 데이터 모델을 랜더링하는 재사용가능한 컴포넌트의 라이브러리를 가질 수 있을 것입니다. 컴포넌트들은 static 버전이기 때문에 render() 메소드만 가지고 있을 겁니다. 컴포넌트의 최상위 계층에서 prop로 데이터 모델을 가져갈 것입니다. 기본 데이터 모델을 변경하고 root.render()를 다시 호출하면 UI가 업데이트 됩니다. 당신은 UI가 어떻게 업데이트 됐는지, 어디가 변경됐는지를 볼 수 있습니다. 리액트의 단방향 데이터 흐름(단방향 바인딩이라고도 불림)은 모든 것을 모듈화하고, 빠르게 유지시켜 줍니다. 

 

이 단계에 대한 실행에 대해 도움이 필요하다면 이 문서를 참고하십시오.

 

막간브리핑 : Props  vs State

리엑트에서 데이터 모델의 타입은 props와 state 두가지가 있습니다. 이 두가지를 구분을 이해하는 것이 중요합니다. 차이점이 확실하지 않은 경우 공식 React문서를 훑어보십시오. 또 props와 state가 무엇이 다른지에 대한 FAQ를 볼 수도 있습니다. 

 

 

3단계 : UI 상태의 최소 표현 식별

UI를 상호작용하게 만들기 위해, 기초 데이터 모델의 변경을 트리거 하는게 필요합니다. 리액트는 이것을 state로 처리합니다. 앱을 정확하게 빌드하기 위해, 앱에서 필요한 변경가능한 상태에 대한 최소한의 셋에 대해 생각해 볼 필요가 있습니다. 핵심은 DRY : 반복하지 마라 입니다. 애플리케이션이 필요로하는 state의 절대적인 최소 표현에 대해 알아내고, 온디멘드가 필요한 그밖에 모든 것을 계산하십시오. 예를 들어, 당신이 만약 TODO 리스트를 만든다면, TODO 아이템들의 배열을 유지하세요. 카운트를 위해 구분된 state 변수를 유지하지 마세요. 대신에, TODO 카운터를 랜더링하길 원할 때, TODO 아이템들의 배열 길이를 가져가세요.

 

우리 예제에 있는 모든 데이터 조각들을 생각해보세요.

  • 상품에 대한 원본 리스트
  • 유저가 입력한 검색 문자
  • 체크박스 값
  • 상품의 필터된 리스트

어떤것이 state인지 알아내 봅시다. 각각의 데이터에 대해 세가지 질문을 해봅시다. 

 

1. props를 통해 부모로부터 전달받았나? 그렇다면 아마 state가 아니다.

2. 시간이 지나도 변하지 않으냐? 그렇다면 아마 state가 아니다.

3. 당신 컴포넌트의 props와 다른 state로 계산이 가능하냐? 그렇다면 state가 아니다.

 

상품에 대한 원본 리스트는 props로 전달된다. 그래서 state가 아니다. 검색문자와 체크박스는 시간이 지나면 변경되고, 다른 것으로부터 계산할 수 없기 때문에 state가 될 수 있을것으로 보인다. 마지막으로 상품의 필터된 리스트는 state가 아닌데, 이유는 상품 원본 리스트에서 검색문자와 체크박스 값으로 계산될 수 있기 때문이다. 

 

그래서 최종적으로 우리 state는 아래와 같다. 

  • 유저가 입력한 검색 문자
  • 체크박스 값

 

4단계 : state가 있어야 하는 장소 판별

좋다. 우리는 앱 state의 최소한의 셋이 무엇인지 알아냈다. 다음으로, 우리는 state가 어느 컴포넌트를 변경시키는지 알아내야 한다. 

 

기억하세요 : 리액트는 컴포넌트 계층을 내려가는 단방향 데이터 흐름이라는 것을요.  이것은 컴포넌트가 어떤 state를 가져야 하는지 명확하지 않을수도 있습니다. 이것이 종종 새로운 개발자가 가장 이해하기 어려운 부분입니다. 이것을 알아내기 위해 다음 단계를 따르세요.

 

  • state를 기준으로 랜더링되는 모든 컴포넌트를 식별하라.
  • 공통으로 소유한 컴포넌트를 찾아라.(단일 컴포넌트 위로 state가 필요한 모든 컴포넌트)
  • 공통 소유자이거나 계층도상 상위에 있는 다른 컴포넌트는 state를 가져야한다.
  • state를 가질만한 컴포넌트를 발견할 수 없다면, state를 가질 수 있는 단일 컴포넌트를 만들어, 공통소유자 구성요소 위의 계층구조 어딘가에 추가하라.

 

이제 우리의 애플리케이션에 이 전략을 통해 실행해봅시다.

 

  • ProductTable은 state를 기준으로 상품리스트를 필터링하기 위해 필요하고, SearchBar는 검색문구와 체크된 state를 표시하기 위해 필요합니다. 
  • 공통 소유 컴포넌트는 FilterableProductTable 입니다. 
  • 이것은 개념적으로 필터 텍스트와 체크된 값이 FilterableProductTable에 살아있게 하기 위해 의미가 있습니다. 

 

그래서, 우리는 우리의 state가 FilterableProductTable에 존재해야 한다고 결정했습니다. 첫째, 애플리케이션에 초기 state값을 반영하기 위해, 인스턴스 프로퍼티 this.state = {filterText:'', inStockOnly: false}를 FilterableProductTable의 constructor에 추가하세요. 그리고, filterText와 inStockOnly를 ProductTable과 SearchBar의 prop으로 전달하세요. 마지막으로 이 props를 ProductTable안에 행을 필터하고, SearchBar안의 폼필드의 값을 세팅하는데 사용하세요.

 

당신은 당신의 애플리케이션이 어떻게 행동하는 지를 볼 수 있습니다: filterText 에 "ball"을 입력하고, 앱을 리프레쉬하세요. 데이터 테이블이 올바르게 업데이트 되는 것을 볼 수 있을 것입니다. 

 

 

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

지금까지, 계층적으로 아래로 흐르는 props와 state의 기능으로 정확히 랜더링하는 앱을 만들었습니다. 이제 데이터가 다른 방향으로 흐르는 것을 지원할 때입니다. 계층도상 깊이 있는 폼 컴포넌트들은 FilterableProductTable내의 state를 업데이트 하기 위해 필요합니다. 

 

리액트는 당신의 프로그램이 어떻게 작업하는 지를 이해를 돕기 위해, 이 데이터 흐름을 명시적으로 만듭니다. 그러나 이것은 전통적인 양방향 데이터 바인딩보다 더 많은 타이핑이 요구됩니다. 

 

만약 당신이 이전 4단계 예에서 체크박스를 체크하거나 타이핑을 시도한다면, 리액트가 당신의 입력을 무시하는 것을 보게 될 것입니다. 이것은 input prop의 값이 FilterableProductTable안으로 전달된 state가 항상 같아지게 하기 위해 의도된 것입니다. 

 

우리는 어떤상황이 발생하길 원하는지 생각해봅시다. 우리는 사용자가 양식을 변경 할 때마다 사용자 입력을 반영하도록 상태를 업데이트 하길 원합니다. 컴포넌트는 오직 자신의 state를 업데이트 할 수 있기 때문에, FilterableProductTable은 state가 업데이트 되었을 때 언제나 실행할 수 있도록, SearchBar로 콜백함수를 전달할것입니다. 우리는 그 사실을 알아차리기 위해 input폼에 onChange 이벤트를 사용할 수 있습니다. FilterableProductTable의해 전달된 콜백함수는 setState()로 불리고, 앱은 업데이트 되어진다. 

 

 

그리고, 이게 다다

희망적이게도, 이것은 리액트로 애플리케이션과 컴포넌트를 만드는 것에 대해 어떻게 생각해야 하는지 아이디어를 준다. 당신이 사용하는 것보다 타이핑이 더 많을수 있지만, 코드는 쓰여진 것보다 더 많이 익히고, 이렇게 모듈화 되고, 명시적 코드를 읽기가 덜 어렵다는 것을 기억하라.

 

 

 

 

반응형