親子コンポーネント
- 目標:複数のコンポーネントを組み合わせて画面を構成する
- 学習:state/props、propsの授受、配列要素の動的表示
概要
stateとprops
- state: 状態を表す変数で、書き換え可能なものです。主に親コンポーネントが使用します。
- props: 状態を受け取るための変数で、読み込み専用です。主に子コンポーネントが使用します。
React第3ポリシーである DATA FLOW は、親から子への単一方向フローと限定しています。この規定を忠実に守ることで、Reactは高速なレンダリングを実現しています。
基本的にReactでは、すべての状態(≒表示データ)は、親が一元的に管理するスタイルをとっています。子たちは親から渡された状態に応じて、自律的に振る舞いを変えるのがReactコンポーネントの特徴です。
子が状態(親state)を変更したい場合は、イベントハンドラを通して、変更の依頼を発火する形を取ります。実際のstateの変更は親が行い、変更が完了したら、親から更新イベントを発行します(setState
)。このイベントハンドラの作成は次節で行います。
実装
親子関係の構築
/assets/react/Main.js
import RoomPane from './RoomPane'
: RoomPaneコンポーネントを使用可能にする。同じプロジェクトの別ファイルをimportする場合は、相対パスで記述できる<RoomPane {...this.state} />
: 自身のstateを、子のpropsとして引き渡す。Spread Attributesを使うと、stateオブジェクトを展開したうえで、propsの一覧として渡せるので便利
'use strict';
import React from 'react';
import RoomPane from './RoomPane';
export default class Main extends React.Component {
constructor() {
super();
// チャットルーム群を状態として保持
this.state = {
rooms: [{
id: 1,
name: 'room1',
messages: [ {id: 1, message: 'asdf'} ]
}, {
id: 2,
name: 'asdf',
messages: [ {id: 2, message: 'qwer'} ]
}],
currentRoom: null
};
this.state.currentRoom = this.state.rooms[0];
}
// ルーム一覧を表示する子コンポーネントを表示
// 自身のstateを、子のpropsとして引き渡している
render() {
return (
<div id="page">
<RoomPane {...this.state} />
</div>
);
}
}
/assets/react/RoomPane.js
- クラス
- RoomPane: ルーム一覧を表示する大枠
- RoomList: ルーム一覧
- Room: 個々のルーム
- テクニック
<RoomList {...this.props} />
: 受け取ったpropsを、さらに自分の子へpropsとして受け流すときに超便利なSpread Attributes構文const roomNodes = this.props.rooms.map((room) => { return JSX; }
: 動的に子コンポーネントを作成するときに使用する構文。propsの要素をイテレーションして、各要素について子コンポーネントを作成する
'use strict';
import React from 'react';
export default class RoomPane extends React.Component {
render () {
// ルーム数と、ルーム一覧コンポーネントを表示
return (
<div id="sidebar">
<h2>Rooms ({this.props.rooms.length})</h2>
<RoomList {...this.props} />
</div>
)
}
}
class RoomList extends React.Component {
render () {
// props.map は、子要素の配列を作るときに便利なイテレーション
// 結果は、ReactElementのArrayとして引き取れる
const roomNodes = this.props.rooms.map((room) => {
return ( <Room key={room.id} {...room} /> );
});
// 配列要素をそのままレンダリング
return (
<ul id="roomList">
{roomNodes}
</ul>
)
}
}
class Room extends React.Component {
render () {
// 今回は単にルーム名を表示する。あとで選択できるようにする予定
return (
<li>
<p>{this.props.name}</p>
</li>
)
}
}