React.jsでComponentの分割をしてみる
Components と Props
コンポーネントを使用すると、UIを独立した再利用可能な部分に分割し、各部分について個別に考えることができます。概念的には、コンポーネントはJavaScript関数のようなものです。彼らは任意の入力(「小道具」と呼ばれる)を受け入れ、何がスクリーンに現れるべきかを記述するReact要素を返します。
関数とClassコンポーネント
コンポーネントを定義する最も簡単な方法は、JavaScript関数を記述することです。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
この関数は、データとともに単一の “props”オブジェクト引数を受け取り、React要素を返すため、有効なReactコンポーネントです。このようなコンポーネントは、文字通りJavaScript関数であるため、「機能的」と呼んでいます。また、ES6クラスを使用してコンポーネントを定義することもできます。というか、これは現時点では古い書き方であり、古い書き方は、新しい書き方と共存しませんので、新しい書き方を学ぶべきです
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
上記の2つの要素は、Reactの観点から見れば全く同等な機能を提供しあmす。クラスに関しては、こっちで説明されているいくつかの追加機能があり、ここで詳しく説明されているので。ここでは、機能部品を簡潔に使用します。
コンポーネントのレンダリング
以前は、DOMタグを表すReact要素のみに遭遇しましたが、
const element = <div />;
ただし、要素はユーザー定義のコンポーネントを表すこともできます。
const element = <Welcome name="Sara" />;
Reactは、ユーザ定義のコンポーネントを表す要素を見ると、JSX属性を単一のオブジェクトとしてこのコンポーネントに渡します。このオブジェクトを「props」と呼びます。たとえば、次のコードでは、ページに「Hello、Sara」と表示されます。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
CodePenで試してみてください。
上記の例で何が起こっているのか見てみましょう
まずReactDOM.render()
で<Welcome name="Sara" />
エレメントを呼んでいます。次にWelcome
コンポーネントでは{name: 'Sara'}
の値を参照しています。Welcome
コンポーネントは結果として<h1> Hello、Sara </ h1>
エレメント(要素)を返します。React DOMは効率的に<h1>Hello, Sara</h1>
DOMを更新して一致させます
注意点:
コンポーネント名は常に大文字で開始してください。
たとえば、<div />はDOMタグを表しますが、<Welcome />はコンポーネントを表し、
ウェルカムをスコープに入れる必要があります。
コンポーネントの作成
コンポーネントは、他のコンポーネントを参照できます。これにより、どの階層に位置するコンポーネントに対しても同じコンポーネントの抽象化を表現できます。ボタン、フォーム、ダイアログ、スクリーン:Reactアプリケーションでは、すべてがコンポーネントとして一般的に表現されます。たとえば、Welcom
を何度もレンダリングするApp
コンポーネントを作成できます。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
//ここ
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
CodePenで試してみてください。
通常、新しいReactアプリケーションには、一番上に1つのコンポーネントがあります。しかし、Reactを既存のアプリケーションに統合する場合、Buttonのような小さなコンポーネントでボトムアップを開始し、徐々にビュー階層の最上位に向かって作業を進めることができます。
注意:
コンポーネントは単一のルート要素を返す必要があるので、すべての<Welcome />要素を含むように<div>を追加しています
コンポーネントの抽出
たとえば、下記のようなコンポーネントを考えてみましょう。
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
CodePenで試してみてください。
大きなコンポーネントを小さなコンポーネントに分割するのを恐れない
全ソース
function formatDate(date) {
return date.toLocaleDateString();
}
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
const comment = {
date: new Date(),
text: 'I hope you enjoy learning React!',
author: {
name: 'Hello Kitty',
avatarUrl: 'https://placekitten.com/g/64/64'
}
};
ReactDOM.render(
<Comment
date={comment.date}
text={comment.text}
author={comment.author} />,
document.getElementById('root')
);
上記のコードではauthor
(オブジェクト)、text
(文字列)、 date
(日付)をpropsとして受け取り、ソーシャルメディアのWebサイトにコメントを記述します。このコンポーネントは、すべてがネストされているため変更するのが難しく、個々の部分を再利用することも困難です。そこからいくつかのコンポーネントを抽出しましょう。まず、「アバター」を抽出します。
function Avatar(props) {
return (
//ここ
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
//ここ
);
}
Avatar
はComment
の中でレンダリングされていることを知る必要はありません。その支柱に author
ではなくuser
というより一般的な名前を与えたのはそのためです。
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
//ここ
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
次に、ユーザーの名前の横にアバターを描画するUserInfoコンポーネントを抽出します。
function UserInfo(props) {
return (
//ここ
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
//ここ
);
}
これにより、さらに単純化することができます。
function Comment(props) {
return (
<div className="Comment">
//ここ
<UserInfo user={props.author} />
//ここ
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
CodePenで試してみてください。
コンポーネントの抽出は、最初は面倒な作業のように思えるかもしれませんが、再利用可能なコンポーネントのパレットを持つことは、より大きなアプリケーションを実現するときに役に立ちます。再利用可能なコンポーネントを創造することを意識しましょう。