React로 사고하기 -1

Jetom·2021년 10월 2일
1

개념정리(react)

목록 보기
7/17
post-thumbnail

요즘 react로 열심히(?) 공부하고 있는데, component를 그리거나 state를 어디서 써야할지 아직도 너무 헷갈려서 읽어보라고 추천받은 react로 사고하기를 블로깅하기로 결정! 글이라서 졸리기도 하지만 최대한 이해한대로 풀어보는거로..😪


공홈 문서 👇

https://ko.reactjs.org/docs/thinking-in-react.html

목업으로 시작하기

목업(mock up = 모형)을 디자이너에게 받았다 가정해 보면 아래의 이미지와 같을 것이다.

또한 JSON API를 받았다면 JSON은 다음과 같은 데이터일것이다.


[
  {
    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"
  }
];

이제 이 data들을 만들때 5단계로 나누어서 차례대로 설명한다.(엄청 길고 많다.. 그리고 초보는 보기 어렵다.. 😭)

1단계: UI를 컴포넌트 계층 구조로 나누기

첫 번째로 할 일은 컴포넌트와 내가 필요한 것들에게 이름을 붙이는 것이다. 만약 디자이너가 있다면 디자이너의 photoshop 레이어의 이름을 보고 짓는것도 도움이 될 수 있다고한다.

그래도 컴포넌트가 되는 기준이 무엇인지 감이 안잡힐 때는 새로운 함수나 객체를 만들 때처럼 하면 된다고한다. (이 말이 이해가 안갔는데, 시멘틱 태그 만들때의 기준처럼 사용하라는 말 같다.🤨) 리액트의 원칙은 단일 책임 원칙이라는 것이다. 즉 하나의 컴포넌트는 하나의 일을 하는것이 이상적이라는 말이다. 만약 하나의 컴포넌트가 몸집이 커지게 된다면 작은 하위 컴포넌트로 분리되어야 한다.

주로 JSON 데이터를 유저에게 보여주게 되며, 만약 모델이 제대로 만들어졌다면 UI가 잘 연결될 것이다. 그 이유는 UI와 데이터 모델은 인포메이션 아키텍처(information architecture)와 서로 깊게 연관되어있기 때문에 컴포넌트를 세부화 시키는 것이 어렵지 않다고 한다.

아래와 같이 컴포넌트가 데이터 모델의 한 조각을 나타내도록 분리 해야 한다.👇

위의 그림을 자세히 살펴보자. 컴포넌트에 들어간 데이터는 이탤릭체로 표기했다.

  1. FilterableProductTable(노란색): 전체를 포괄하는 layout
  2. SearchBar(파란색): 유저의 입력을 받음
  3. ProductTable(연두색): 입력받은 데이터필터링 해서 보여준다.
  4. ProductCategoryRow(하늘색): 각 카테고리의 헤더를 보여준다.
  5. ProductRow(빨강색): 제품의 행을 보여준다.

ProductTable(3번)을 보면 "name"과 "price" 레이블(= 무엇을 입력해야 할 지 알려주는 역할)을 포함한 테이블 헤더는 컴포넌트에 존재하지 않는다. 이 문제는 데이터를 위한 독립된 컴포넌트를 생성할지 말지의 선택의 문제이다. ProductTable의 책임인 data collection(= 데이터 컬렉션: 데이터의 집합을 수집)이 렌더링의 일부이기 때문에 ProductTable을 남겨두었지만 기능이 복잡해진다면 ProductTableHeader 컴포넌트를 만드는 것이 합리적이다.

이제 layout을 확인 했으므로 계층 구조로 나열해본다면 아래와 같다.

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

2단계: React로 정적인 버전 만들기

<!-- html -->
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

/* css */
body {
    padding: 5px
}

//react

class ProductCategoryRow extends React.Component {
  render() {
    const category = this.props.category;
    return (
      <tr>
        <th colSpan="2">
          {category}
        </th>
      </tr>
    );
  }
}

class ProductRow extends React.Component {
  render() {
    const product = this.props.product;
    const name = product.stocked ?
      product.name :
      <span style={{color: 'red'}}>
        {product.name}
      </span>;

    return (
      <tr>
        <td>{name}</td>
        <td>{product.price}</td>
      </tr>
    );
  }
}

class ProductTable extends React.Component {
  render() {
    const rows = [];
    let lastCategory = null;
    
    this.props.products.forEach((product) => {
      if (product.category !== lastCategory) {
        rows.push(
          <ProductCategoryRow
            category={product.category}
            key={product.category} />
        );
      }
      rows.push(
        <ProductRow
          product={product}
          key={product.name} />
      );
      lastCategory = product.category;
    });

    return (
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Price</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
}

class SearchBar extends React.Component {
  render() {
    return (
      <form>
        <input type="text" placeholder="Search..." />
        <p>
          <input type="checkbox" />
          {' '}
          Only show products in stock
        </p>
      </form>
    );
  }
}

class FilterableProductTable extends React.Component {
  render() {
    return (
      <div>
        <SearchBar />
        <ProductTable products={this.props.products} />
      </div>
    );
  }
}


const PRODUCTS = [
  {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'}
];
 
ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('container')
);

앱을 가장 쉬운 방법으로 구현하려면 데이터 모델을 가지고 UI를 렌더링 하지만 아무 동작하지 않는 버전을 만드는것이다. 데이터 모델을 렌더링하는 앱의 정적 버전을 만들기 위해 다른 컴포넌트를 재사용하는 컴포넌트를 만들고 props를 이용해 데이터를 전달해주자. 정적 버전을 만들기 위해 state를 사용하지 않아야한다. 그 이유는 state는 시간이 지남에 따라 데이터가 바뀌는 것에 사용해야한다.

앱을 만들 때 하향식(top-down)이나 상향식(bottom-up)으로 만들 수 있다. 즉 FilterableProductTable(= 전체를 포괄하는 layout)부터 시작하거나 ProductRow(= 제품의 행)부터 만들 수 있다는 것이다. 보통 하향식으로 만드는 것이 쉽지만 프로젝트가 커진다면 상향식으로 만들고 테스트를 작성하면서 개발하기가 더 쉽다.

이 단계가 끝나면 데이터 렌더링을 위해 만들어진 재사용 가능한 컴포넌트의 라이브러리를 가지게 되지만 지금의 프로젝트는 render() 메서드만 가지고 있을것이다. 최상단 컴포넌트(= FilterableProductTable)는 prop으로 데이터 모델을 받는다. 만약 데이터 모델이 변경되면 ReactDOM.render()를 다시 호출해 UI가 업데이트 된다. React는 단방향 데이터 흐름(one-way data flow) (또는 단방향 바인딩(one-way binding))는 모든 것을 모듈화 하고 빠르게 만들어준다. 따라서 UI가 어떻게 업데이트되고 어디에서 변경해야하는지 알 수 있다.

👉 지금까지의 단계가 어렵다면? react 시작하기

👉 state와 props의 차이가 헷갈린다면? state와 props의 차이점은 무엇인가요?


profile
사람이 좋은 인간 리트리버 신혜리입니다🐶

0개의 댓글