12. Composition vs Inheritance - accgetter/React GitHub Wiki
Reactは強力な構成型モデルなので、 コンポーネント間でコードを再利用する場合継承の代わりに使用する事をお勧めします。
このセクションでは、新たにReactを使用する際の継承の問題について考え、構成型モデルでどのように解決するかみてみましょう。
コンポーネントでは最初にどのような子コンポーネントをもつか知る事のできない場合もあります。
Sidebar
やDialog
のようなよくある"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>
);
}
<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 />
} />
);
}
<Contacts />
や<Chat />
のようなReactの要素はオブジェクトなので、propsとして他のデータと同じように渡す事ができます。
たまに、例外的なコンポーネントについて考えます。例えば、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!" />
);
}
構成型モデルはクラスとして定義されたコンポーネントで同じように効果を発揮します:
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}!`);
}
}
Facebookでは、何千ものコンポーネントを使っていて、継承された階層型のコンポーネントを使うべき箇所はありません。
Props と 構成型モデルは柔軟なカスタマイズ性を明確で安全な方法で提供してくれます。
コンポーネントは大体どんなpropsも受け取れる事を忘れないでください、プリミティブな値でも、Reactの要素でも、関数でもOKです。
もし、コンポーネント間でUIでない機能を再利用したい場合は、Javascriptの形式で取り出す事をお勧めします。
コンポーネントはそれをインポートし、ファンクションでも、オブジェクトでも、クラスでも拡張する事なしに利用する事ができます。