12. Composition vs Inheritance - accgetter/React GitHub Wiki

Reactは強力な構成型モデルなので、 コンポーネント間でコードを再利用する場合継承の代わりに使用する事をお勧めします。
このセクションでは、新たにReactを使用する際の継承の問題について考え、構成型モデルでどのように解決するかみてみましょう。

Containment

コンポーネントでは最初にどのような子コンポーネントをもつか知る事のできない場合もあります。
SidebarDialogのようなよくある"boxes"では特にそうだと思います。

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

Try it on CodePen.

<FancyBorder>内全部のJSXタグをFancyBorderコンポーネントにchildren prop として渡します。
FancyBorder{props.children}<div>の中で描画するので, 渡された要素は最終的な表示で出力されます。

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

Try it on CodePen.

<Contacts /><Chat />のようなReactの要素はオブジェクトなので、propsとして他のデータと同じように渡す事ができます。

Specialization

たまに、例外的なコンポーネントについて考えます。例えば、WelcomeDialogを特別なDialogとしてみましょう。

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

Try it on 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}!`);
  }
}

Try it on CodePen.

So What About Inheritance?

Facebookでは、何千ものコンポーネントを使っていて、継承された階層型のコンポーネントを使うべき箇所はありません。
Props と 構成型モデルは柔軟なカスタマイズ性を明確で安全な方法で提供してくれます。
コンポーネントは大体どんなpropsも受け取れる事を忘れないでください、プリミティブな値でも、Reactの要素でも、関数でもOKです。
もし、コンポーネント間でUIでない機能を再利用したい場合は、Javascriptの形式で取り出す事をお勧めします。
コンポーネントはそれをインポートし、ファンクションでも、オブジェクトでも、クラスでも拡張する事なしに利用する事ができます。

⚠️ **GitHub.com Fallback** ⚠️