コンポジション vs 継承
を参考に初心者がわからないけど覚書を書いています。
React は強力なコンポジションモデルを備えており、コンポーネント間のコードの再利用には継承よりもコンポジションをお勧めしています。
コンポジションって何?
-
Reactにおけるコンポジションとは?
Reactでアプリを作成する場合、ヘッダ・フッタ・サイドバー・メニューなどの部品をコンポーネントによって作成します。Reactでアプリを作成する際には、コンポーネントをどのように分割して構成するかが重要となります。これを「Reactコンポーネントのコンポジション」と呼びます。
(わかりやすい解説) -
ひとつひとつの Reactコンポーネントは関数のようなものですが、それらを組み合わせてコンポジションによってカスタマイズできる
-
どんな子要素が入るのか決まっていないコンポーネントがある場合
- children という特別な機能を持つ props を使うことができます。childrenは 子要素を渡すための専用の props
- childrenに任せた!みたいな感じ?
子要素の出力 (Containment)
- コンポーネントの中には事前には子要素を知らないものもある。“入れ物(Sidebar,Dialogなど)” をあらわすコンポーネントではよく使われる
- JSX タグの内側のあらゆる要素は FancyBorder に children という props として渡される
import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import './index.css';
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="ようこそ!"
message="you are welcome!!" />
);
}
ReactDOM.render(
<WelcomeDialog />,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
.FancyBorder{
padding: 10px;
border: solid 10px;
text-align:center;
}
.FancyBorder-blue{
border-color: #00f;
}
.Dialog-title{
margin:0;
font-family:sans-serif;
/* text-align:center; */
}
複数の箇所に子要素を追加したいケース(一般的ではない)
- や のような React の要素はただのオブジェクトなので、他のあらゆるデータと同様に props として渡すことができる
- 他のライブラリでいうと、slot に似ている
- propsに渡せるものに制限はない
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 />
} />
);
}
特化したコンポーネント (Specialization)
?何が特化なのかよくわからなかった
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>
</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 abroad, ${this.state.login}!`);
}
}
継承は?
-
コンポーネント継承による階層構造が推奨されるケースは全く見つかっていない
?ここもよくわからなかった -
コンポーネントはどのような props でも受け付けることができ、それはプリミティブ値でも、React 要素でも、あるいは関数であってもよい、ということに留意
-
コンポーネント間で非 UI 機能を再利用したい場合は、それを別の JavaScript モジュールに抽出することをお勧めする