親子コンポーネント

  • 目標:複数のコンポーネントを組み合わせて画面を構成する
  • 学習: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: 個々のルーム
  • テクニック
    • &lt;RoomList {...this.props} /&gt; : 受け取ったpropsを、さらに自分の子へpropsとして受け流すときに超便利なSpread Attributes構文
    • const roomNodes = this.props.rooms.map((room) =&gt; { 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>
    )
  }
}