개발 공부/React

가장 쉬운 리액트 10강

5묘 2022. 12. 16. 11:05
가장 쉬운 웹개발 with Boaz

10.Composition vs Inheritance

 

10.Composition vs Inheritance

(React 공식문서의 main concepts 번역 글입니다.) 함께보면 이해가 쏙쏙https://youtu.be/T6Wj2pbkorA 과 는component를 만드는 2가지 다른 패턴이다.(https://www.youtube.com/watch?time_continue=238&v=wfMtDGfHWpA)(위 영상을 참

davidhwang.netlify.app

더보기

composition과 inheritance는
component를 만드는 2가지 다른 패턴이다. 둘 다 중복을 제거하기 위해 사용한다.
(https://www.youtube.com/watch?time_continue=238&v=wfMtDGfHWpA)
(위 영상을 참고하면 둘의 차이를 쉽게 이해할 수 있다.)

++ composition은 내가 가지고 있지 않은 공통된 속성을 함께 사용할 수 있다.
하지만 inheritance는 내가 가지고 있는 것을 그대로 물려준다. 갖고 있지 않은 건 쓸 수 없다.
React는 composition을 추천한다. inheritance는 한계에 부딪히기 때문이다.

보충 설명을 하자면
composition은 component가 무엇을 하는지를 기준으로 선언한다.
반면 inheritance는 component가 무엇인지를 기준으로 선언한다. 

React에서 inheritance를 활용하면 코드 재사용성이 낮다.
반면에, composition model은 재사용성이 높다.
inheritance로는 재사용할 수 없는 상황이 있기 때문이다.

바로 그 한계상황에 대해, 아래에서 살펴볼 것이다.
또한 composition으로 그 한계상황을 어떻게 극복할 수 있는지
그 해결방법도 함께 살펴 볼 것이다.

Containment

어떤 type의 props를 받을 지 알 수 없는 상황에서 component를 만들 경우,
inheritance는 내가 어떤 props를 줄지 가지고 있어야만 하는데, composition은 외부에 공통된 특성 있으면
그냥 그거 전달받아 쓰면 되므로 중복 줄일 수 있다.

첫번째 한계상황인 containment이다.
어떤 component가 children 값을 미리 알 수 없는 경우가 있다.
보통 Sidebar  Dialog가 이에 해당한다.
(일반적으로 박스 형태의 component가 이에 속한다.)

그런 경우에는 해당 component가 return하는 react element안에
직접 {children props}를 넣어주는 것이 좋다.
그 결과, 어떠한 children props를 받더라도 render가 가능해진다.

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

위 코드와 같이 return하는 element에
직접 {children props}를 넣으면
아래처럼 해당 component에게 다른 component가
tag 모음의 children을 props로 전달하더라도 render가 가능하다.

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
  ***
      <h1 className="Dialog-title">        
          Welcome      
      </h1>      
      <p className="Dialog-message">        
          Thank you for visiting our spacecraft!      
      </p>    
  ***	
      </FancyBorder>
  );
}

위에서 하이라이팅된 부분, 즉 tag 모음 뿐만아니라
어떠한 것도 <FancyBorder> JSX tag 로 감싸기만 하면 <FancyBorder>는 children props로 전달받을 수 있다.
<FancyBorder>는 <div>로 감싸진 {props.children}을 return하므로
children props로 전달 받은 어떠한 것이든 render할 수 있다.

특수한 경우에, 여러개의 {props.children}가 필요할 수도 있다.
그러한 경우에는 children보다는 더 정확히 표현할 수 있는 이름을 사용한다.

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 />      
      } />
  );
}

<Contacts />나 <Chat />같은 react element는 객체이다.
따라서 react element들은 다른 data처럼 props로 전달할 수 있다.

Specialization

두번째 한계상황은 특별한 component가 필요한 경우이다.
이 경우, 일반적인 component를 수정하여 특별한 component를 만든다.

예를 들어 <Dialog>는 일반적인 component이다.
이를 수정하면 특별한 component <WelcomeDialog>를 만들 수 있다.

React에서 특별한 component는 composition으로 만들 수 있다.
즉 일반적인 component에게 props를 주어 특별한 component로 만든다.

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!" />
  );
}

일반적인 component인 <Dialog>에
title과 message props를 주어
특별한 component <WelcomeDialog>를 만들었다.

function component 뿐아니라 class component에서도
composition으로 동일하게 specialization을 할 수 있다.

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

class SignUpDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSignUp = this.handleSignUp.bind(this);
    this.state = {login: ''};
  }

  render() {
    return (
      <Dialog title="Mars Exploration Program"
              message="How should we refer to you?">
         *** // 이게 다 props.children
        <input value={this.state.login}              
               onChange={this.handleChange} />        
        <button onClick={this.handleSignUp}>          
        	Sign Me Up!        
        </button>   
     	 ***
      </Dialog>
    );
  }

  handleChange(e) {
    this.setState({login: e.target.value});
  }

  handleSignUp() {
    alert(`Welcome aboard, ${this.state.login}!`);
  }
}

inheritance를 사용하면 어떻게 되지?

페이스북에서는 composition을 활용하여 component를 만든다.
왜냐하면 inheritance보다 효율이 좋기 때문이다.

props와 composition을 활용하면 일반적인 component
명백하고 안전하게, 특별한 component로 만들 수 있게 된다.
그 component는 임의의 props(primitive value, function,
심지어 react element까지)를 받아들일 수 있기 때문이다.

만약 UI로직과 관련이 없는 function을 재사용 하기 원한다면
해당 function을 extract하는 것을 추천한다.
특정 component가 해당 function이 필요하면 import해서 쓸 수 있다.(props로!)
inheritance를 통해 function 코드를 재사용하는 대신에!

'개발 공부 > React' 카테고리의 다른 글

가장 쉬운 리액트 12강  (0) 2022.12.16
가장 쉬운 리액트 11강  (0) 2022.12.16
가장 쉬운 리액트 9강  (0) 2022.12.16
가장 쉬운 리액트 7~8강  (0) 2022.12.15
[TIL] virtual DOM  (0) 2022.12.15