리액트 공식 문서 정리 - 합성 vs 상속 & 리액트로 사고하기

Jessie H·2022년 9월 7일
0

react

목록 보기
10/13
post-thumbnail

합성

컴포넌트에 다른 컴포넌트 담기

  • 보통 다른 컴포넌트를 담는 "박스"역할을 하는 컴포넌트에서 많이 볼 수 있다

props.children 활용하여 단순한 기능을 가진 컴포넌트로 만들기

//박스 역할을 하는 FancyBorder component
//무엇이 들어올지 알 수 없으므로 children props를 담아 보여주도록 한다

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  );
}

//환영하는 안내 문구 박스를 반환하는 WelcomeDialog
function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

파란 박스 부분: <FancyBorder>
--> WelcomeDialog 안에 FancyBorder을 담음
props.children으로 담기는 컴포넌트를 보여주기만 하는 역할을 하므로 재사용성이 높고 의존성도 낮다

여러개의 구멍이 필요할 경우

  • 특수한 props로 여러 개의 구멍을 만든다.(left, right / up, down 등)
function Contacts() {
  return <h1 className="Contacts">This is Contacts</h1>;
}

function Chat() {
  return <h1 className="Chat">This is Chat</h1>;
}

//Contacts와 Chat을 담는 박스 역할의 컴포넌트
function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

빨간색 테두리: SplitPane 컴포넌트
하늘색: Contacts 컴포넌트
분홍색: Chat 컴포넌트


컴포넌트 특수화하기

(컴포넌트 내에 내용을 또 컴포넌트화 해서 컴포넌트를 여러개 만들더라도 최대한 단순화 시키려고 하는 과정이라고 생각)

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  );
}

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
    </FancyBorder>
  );
}

function WelcomeDialog() {
  return (
    <Dialog
      title="Welcome"
      message="Thank you for visiting our spacecraft!" />
  );
}

FancyBorder: props.children의 내용을 담을 수 있는 파란색 박스 컴포넌트
|
Dialog: FancyBorder를 포함해서 title과 message를 보여주는 컴포넌트
|
WelcomeDialog: Dialog에 Welcome title과 message를 담아 만든 특수한 Dialog

이런 방식으로 컴포넌트를 더 단순화시키면 컴포넌트의 재활용성이 높아진다.

상속

  • 리액트에서는 컴포넌트는 다른 컴포넌트로 직접 상속하지 않고 다른 컴포넌트를 만들어서 보여줄 내용을 props로 넘겨주어 활용하는 방식으로 처리한다(위의 두 방법으로 처리)

리액트로 사고하기

1단계: UI별로 컴포넌트 구분하기

  • 하나의 파일 안에 다 코딩을 한 Mock-up version을 UI별로 컴포넌트를 구분한다.


2단계: 정적 버전 만들기

  • 다른 컴포넌트를 재사용하는 컴포넌트를 만들고 props 를 이용해 데이터를 전달
  • 상향식으로 만들기 or 하향식으로 만들기
    • 상향식: 위의 예시에서는 productRow부터 만들기
      (세부적인 것부터 시작해서 세부적인 것을 담는 컨테이너 만드는 방식)
    • 하향식: 위의 예시에서는 FilterableProductTable부터 만들기
      (가장 바깥부분의 컨테이너부터 그 컨테이너를 구성하는 세부 컴포넌트 순으로 만드는 방식)

이렇게 만들게 되면 UI가 어디서 업데이트되고 어디에서 변경을 해야하는지 알 수 있다
(어떤 것을 state로 만들어야할 지 좀 더 알기 쉬워짐)


3단계: UI에서 state를 가장 적게 쓸 수 있는 최소 집합을 생각하기

state로 만들어야 할지 말지 고민될 때

  • 부모로부터 props를 통해 전달된다면? NOT state
  • 시간이 지나도 변하지 않는다? NOT state
  • 컴포넌트 안의 다른 state나 props를 가지고 계산이 가능하다면? NOT state

ex) 위의 예시 Todo App

<포함한 내용>
- Todo Mock data list 
-> 시간이 지나도 변하지 않는다

- 유저가 입력한 검색어 
  -> 부모로부터 전달받을 수 없다, 
  -> 시간이 지나면 입력한 값에 따라 변한다, 
  -> 다른 state나 props를 가지고 계산할 수 없다 -> "state"

- 체크박스의 값
  -> 부모로부터 전달받을 수 없다
  -> 시간이 지나 체크를 하거나 체크를 풀게 되면 변한다.
  -> 다른 state나 props로 체크 여부를 알 수 없다 -> "state"
  
- 필터링 된 제품들의 목록
  -> props(mock data)로 계산하여 부모에서 자식으로 전달할 수 있다
  -> 시간에 따라 변한다기 보다는 조건에 따라 변한다.

4단계: State가 어디에 있어야 할지 찾기

ⓐ state를 기반으로 렌더링하는 모든 컴포넌트를 찾기
ⓑ 공통 소유 컴포넌트 찾기(해당 state를 필요로하는 형제 컴포넌트들의 부모 컴포넌트를 찾기)
ⓒ state를 소유할 컴포넌트를 찾지 못했을 경우 state를 소유하는 컴포넌트를 하나 만들어
공동 소유 컴포넌트의 상위 계층에 추가하기

Todo App 예시에서 state 위치 찾기
SearchBar -> 검색어와 체크박스 체크 여부 필요
ProductTable -> 검색어와 체크박스 체크 여부 조건을 바탕으로 상품을 필터링해서 보여주어야 함
FilterableProductTable이 SearchBar과 ProductTable를 포함 -> state를 저장할 위치


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

부모 컴포넌트에서 부모 컴포넌트의 state를 업데이트 할 자식 컴포넌트로 setState를 props로 전달하여 앱이 업데이트 되도록 한다.


모든 코드 및 사진 출처:
공식문서 및 공식문서에 연결된 codepen

profile
코딩 공부 기록장

0개의 댓글