https://reactjs.org/docs/composition-vs-inheritance.html - 번역 글

React는 강력한 구성 모델을 가지고 있으며 상속 대신 구성을 사용하여 컴포넌트 사이의 코드를 재활용하는 걸 권장합니다.

이 섹션에서는 React를 처음 사용하는 개발자가 상속을 위해 종종 도달하는 몇 가지 문제를 살펴보고 구성을 통해 문제를 해결할 수있는 방법을 보여줍니다.


Containment(방지)

일부 컴포넌트는 자식를 미리 알지 못합니다. 이는 일반적으로 박스로 사용되는 Sidebar또는 Dialog같은 컴포넌트가 그렇습니다.

이러한 컴포넌트는 특수한 children prop을 사용하여 자식 요소를 출력에 직접 전달하는 것이 좋습니다.

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

이렇게하면 JSX를 중첩하여 다른 컴포넌트가 임의의 자식을 전달할 수 있습니다.

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

CodePen

<FancyBorder> 컴포넌트 내부에 작성된 JSX는 모두 FancyBorder컴포넌트의 children로 전달됩니다. FancyBrorder{props.children}<div> 안에 렌더링하므로 전달된 요소는 최종 출력에 나타납니다.

자주 사용되지는 않지만 구성 요소에 여러 개의 구멍이 필요할 수 있습니다. 이런 경우에는 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 />
      } />
  );
}

CodePen

<Contacts /><Chat /> 같은 React 요소는 단순 객체로 어떤 다른 데이터든 props를 통해 전달할 수 있습니다. 이것은 다른(Vue) 라이브러리의 slots(슬롯)를 생각나게할 수 있지만 React에서 props로 전달할 수 있는 것에는 제한이 없습니다.


Specialization(특수화)

가끔 컴포넌트가 다른 컴포넌트의 특수한 경우 (special case) 라고 생각합니다. 예를 들어 WelcomeDialogDialog의 특수한 경우라고 말할 수 있습니다.

React에서는 콤포지션 (composer)을 사용합니다. 더 구체적인 컴포넌트가 범용구성 요소를 렌더링하고이를 props으로 구성합니다.

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!" />

  );
}

CodePen

컴포지션은 클래스로 정의 된 컴포넌트에도 똑같이 적용됩니다.

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

CodePen


So What About Inheritance?(그래서 상속이 어떤가?)

Facebook에서는 수천 개의 구성 요소에서 React를 사용하며 구성 상속 계층 구조를 만드는 것이 권장되는 사용 사례는 찾지 못했습니다.

props와 구성은 명시적이며 안전한 방법으로 컴포넌트의 모양과 동작을 커스터마이징하는 데 필요한 모든 유연성을 제공합니다. 컴포넌트는 기본 값, React 요소 함수를 비롯한 임의의 props를 수용할 수 있습니다.

컴포넌트 간 UI가 아닌 기능을 재사용하려면 별도의 자바스크립트 모듈로 추출하는 것이 좋습니다. 컴포넌트는 이를 가져오거나 함수, 객체 또는 클래스를 확장하지 않고 사용할 수 있습니다.