[React] React로 사고하기

YIM_JI·2023년 5월 10일
0

react

목록 보기
2/2

React로 사고하기

현재 나는 학원 동료들과 간단한 웹앱을 react(이하 리액트)로 만들려고 하고 있다. 그러다 보니 리액트로는 어떻게 설계를 해야 되고 어떤 구조로 프로젝트를 만들어야 하는지 궁금증이 생겼다. 그래서 이곳 저곳 블로그를 보다가 일단 공부를 좀 더 하자 하고 공식문서를 봤는데 'React로 사고하기' 페이지가 있었다. 쭉 읽어봤는데 처음 리액트를 시작할 때 도움이 될 거 같아 간단하게 나마 블로그로 남긴다.



Step 1: Break the UI into a component hierarchy (UI를 컴포넌트 계층 구조로 나누기)

구현하고자 하는 UI를 컴포넌트 계층으로 나눈다. 컴포넌트는 어떻게 나눠야 될까?

  • 프로그래밍 - 새 함수나 객체를 생성할지 여부를 결정할 때 동일한 기법을 사용합니다. 이러한 기법 중 하나는 단일 책임 원칙으로, 컴포넌트는 이상적으로는 한 가지 일만 수행해야 한다는 것입니다. 만약 컴포넌트가 늘어나게 되면 더 작은 하위 컴포넌트로 분해해야 합니다.
  • CSS - 클래스 선택자를 만들 때 무엇을 위해 만들 것인지 생각해 보세요. (단, 컴포넌트는 조금 덜 세분화되어 있습니다.)
  • 디자인 - 디자인의 레이어를 어떻게 구성할지 고려하세요.

<출처> 리액트 공식문서 이미지

위에 색깔네모로 그려저 있는 것이 컴포넌트라고 보면 된다.
저것들을 각각 컴포넌트로 만들어야 될 거 같다.


Step 2: Build a static version in React (React로 정적인 UI 만들기)

단순히 UI(정적 버전)를 만든다. 정적인 UI를 만들 때는 타이핑이 많이 필요하고 고민은 크게 필요하지 않은 반면, 사용자와의 상호작용 기능을 추가할 때는 타이핑보다 고민이 많이 필요하다고 공식문서가 그런다ㅎㅎ

정적 버전을 만들기 위해서는 재사용되는 components를 만들고 props를 이용해서 데이터를 전달해야 한다고 한다. props는 부모에서 자식으로 데이터를 전달하는 방식이고 정적 버전을 만들 때는 state를 아예 사용하지 말라고 한다! 뒤에 가면 state를 최소화하라고 나온다. state가 바뀔 때마다 재렌더링되니 비용이 비싸서 그런 거 같다.

또 큰 컴포넌트부터 만들 것인지 작은 컴포넌트부터 만들 것인지 정해야 하는데 간단한 예시는 하향식(큰 컴포넌트부터, top-bottom)으로 진행하는 것이 더 쉽고, 대규모 프로젝트에서는 상향식(작은 컴포넌트부터, bottom-top)으로 진행하는 것이 더 쉽다고 한다. 나는 평소 하향식이 익숙하나 공식문서의 조언대로 이번엔 상향으로 해봐야겠다.

또 재사용 가능한 컴포넌트를 갖게 되는데 데이터는 맨 위에 있는 컴포넌트가 prop으로 전달한다고 한다. 아마 위에 나와 있는 것처럼 단일 책임을 주려고 그러는 거 같다. (흠.. 이러면 뭔가 prop chain이 발생할 거 같은데.. 해결방법을 어디서 본 거 같은데 찾아봐야겠다..!)

Step 3: Find the minimal but complete representation of UI state (최소한의 완전한 UI state 찾기)

state를 앱이 기억해야 하는 최소한의 변화하는 데이터의 집합으로 보라고 한다. state를 계획할 때 가장 중요한 원칙은 DRY(Don't Repeat Yourself) 라고 한다. 사용할 수 있는 최소한으로 state를 사용하고 state를 이용해 계산할 수 있는(활용할 수 있는) 데이터들은 state로 두지 말라는 말인 거 같다. 예를 들어, 게시판에서 게시글을 state배열로 두면 게시글의 개수는 state로 두는 것이 아니라 게시글배열.length를 이용해 구하면 된다.

아래는 공식문서 예시가 너무 좋아서 직접 인용하겠다.

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

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

다음 중 어떤 것이 state인가요? 그렇지 않은 것을 식별합니다:

  • 시간이 지나도 변하지 않나요? 그렇다면 state가 아닙니다.
  • 부모로부터 props를 통해 전달되나요? 그렇다면 state가 아닙니다.
  • 컴포넌트의 기존 state 또는 props를 가지고 계산할 수 있나요? 그렇다면 당연히 state가 아닙니다!

남은 것이 아마도 state일 것입니다.
다시 한 번 하나씩 살펴봅시다:

  • 제품 원본 목록은 props로 전달되었으므로 state가 아닙니다.
  • 검색어는 시간에 따라 바뀌고 다른 것으로부터 계산할 수 없으므로 state로 볼 수 있습니다.
  • 체크박스의 값은 시간에 따라 바뀌고 다른 것으로부터 계산할 수 없으므로 state로 볼 수 있습니다.
  • 필터링된 제품 목록은 원본 목록으로부터 검색어 및 체크박스 값을 조합하여 계산할 수 있으므로 state가 아닙니다.

즉, 검색어와 체크박스의 값만 state입니다! 멋지네요!

💡 다 읽고 나니 뭔가 사용자의 의해 데이터가 바뀔 때 state를 쓰는 것 같다.

props와 state 차이

  • Props는 함수가 전달받는 인자와 같습니다. 부모 컴포넌트가 자식 컴포넌트에 데이터를 넘겨서 자식의 외관을 커스터마이징할 수 있게 해줍니다. 예를 들어 Form은 color prop을 Button에 전달할 수 있습니다.
  • State는 컴포넌트의 메모리와 같습니다. state는 컴포넌트가 일부 정보를 계속 추적하고 상호작용하여 변화할 수 있게 해줍니다. 예를 들어, Button은 isHovered state를 추적할 것입니다.

Step 4: Identify where your state should live (state가 어디에 있어야 할지 파악하기)

state를 최소한으로 정했다면 state가 어느 컴포넌트에 있어야 할 지 정해야 한다. 아직 처음이라 익숙하지 않을 수 있지만 다음 단계를 따르면 이해할 수 있을 거라고 한다.

  1. 해당 state를 기반으로 렌더링하는 모든 컴포넌트를 찾아라.
  2. 가장 가까운 공통 상위 컴포넌트, 즉 계층상 그 state의 영향을 받는 모든 컴포넌트들의 위에 있는 컴포넌트를 찾아라.
  3. state가 어디에 위치할지 결정합시다:
  4. 대개 공통 부모에 state를 그대로 둘 수 있습니다.
  5. 혹은 공통 부모보다 더 상위 컴포넌트에 state를 둘 수도 있습니다.
  6. state를 소유할 적절한 컴포넌트를 찾지 못했다면, state를 소유하는 새 컴포넌트를 만들어 공통 부모 컴포넌트보다 상위에 추가하세요.

위의 공식문서의 UI를 참고하며 다음 글을 읽어보자.

  1. state를 사용하는 컴포넌트들 식별하기:
    • ProductTable은 해당 state(검색어 및 체크박스 값)를 기반으로 제품 목록을 필터링해야 합니다.
    • SearchBar는 해당 state(검색어 및 체크박스 값)를 표시해야 합니다.
  2. 공통 부모 찾기: 두 컴포넌트가 공유하는 첫 번째 부모 컴포넌트는 FilterableProductTable입니다.
  3. state를 어디에 둘지 결정하기: FilterableProductTable에 filter text와 checked state 값을 유지합니다.

이제 state 값은 FilterableProductTable에 있습니다.


Step 5: Add inverse data flow (역방향 데이터 흐름 추가하기)

위의 상태대로라면 부모에서 state를 관리하고 자식에게 props로 데이터를 전달해주는 단방향 구조다. 그러나 자식에서 props 데이터가 변경되었을 때 state를 업데이트 해야 하므로 역방향으로도 데이터가 흐를 수 있게 해줘야 한다.

현재 setState 함수는 부모만 갖고 있으므로 자식에게 props로 전달해준다.

function FilterableProductTable({ products }) {
  const [filterText, setFilterText] = useState('');
  const [inStockOnly, setInStockOnly] = useState(false);

  {/* 아래 setState 함수들을 전달해준다. */}
  return (
    <div>
      <SearchBar 
        filterText={filterText} 
        inStockOnly={inStockOnly}
        onFilterTextChange={setFilterText}
        onInStockOnlyChange={setInStockOnly} />

자식은 이 함수를 받아서 사용자에 의해 값이 바뀔 때마다 state를 업데이트해준다.

<input 
  type="text" 
  value={filterText} 
  placeholder="Search..." 
  onChange={(e) => onFilterTextChange(e.target.value)} />

여기가 'React로 사고하기' 공식문서 끝이다.
여기서 눈여겨봐야할 점은
1. UI를 컴포넌트로 쪼개기
2. state는 최소한으로
3. state관리는 같이 쓰이는 자식들의 부모가, 없다면 부모를 만들어서 거기서 관리하고 state, setState는 props로 자식에게 전달한다.

이 정도일 거 같다. 공식문서가 잘 되어있어서 읽기도 좋고 재밌다ㅎㅎ 개발하다가 중간중간 돌아와서 보면 도움이 많이 될 거 같다!!

0개의 댓글