react.js

React.jsチュートリアルをやる(2)

More than 1 year has passed since last update.

React.jsチュートリアルをやる(1)のつづき。

サーバからデータを取得する

ルートコンポーネントから渡していくデータの取得先をサーバに変える。

ReactDOM.render(
- <CommentBox data={data} />,
+ <CommentBox url="/api/comments" />,
  document.getElementById('content')
);

この時点ではまだ動かない。サーバからデータを取得したタイミングで、コンポーネントを更新する必要がある。

コンポーネントの読み込みの基本形は<CommentBox />。読み込むコンポーネントにデータを渡したい場合は<CommentBox data={data} />のように書く。読み込まれたコンポーネント内でthis.props.dataのように書くことで、このデータにアクセスできる。
上のコードでは<CommentBox url="/api/comments" />としてるので、CommentBoxコンポーネント内でthis.props.urlと書くことでurlを取得することができる。

Reactive state

(1)で親コンポーネントから子コンポーネントへのデータの引き渡しにpropsを使ったが、propsはイミュータブルのため、親から受け継いだ値の変更ができない。親と子でインタラクティブにデータのやり取りをするためにはpropsではなくstateを使う。

var CommentBox = React.createClass({
+ getInitialState: function() {
+   return {data: []};
+ },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
-       <CommentList data={this.props.data} />
+       <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

CommentListへのデータの受け渡しを{this.props.data}から<CommentList data={this.state.data}に変更した。こうすることで、サーバからデータを取得したタイミングでthis.setState()を使いCommentListコンポーネントを更新することができる。

またgetInitialState()はコンポーネントのライフサイクルにおいて最初の一度だけ実行され、初期値を設定することができる。

stateの更新

コンポーネント作成時にjsonデータをサーバから取得し、データを最新のものに更新してみる。今回jsonデータ取得はajaxで行う。

var CommentBox = React.createClass({
+ loadCommentsFromServer: function() {
+   $.ajax({
+     url: this.props.url,
+     dataType: 'json',
+     cache: false,
+     success: function(data) {
+       this.setState({data: data});
+     }.bind(this),
+     error: function(xhr, status, err) {
+       console.error(this.props.url, status, err.toString());
+     }.bind(this)
+   });
+ },
  getInitialState: function() {
    return {data: []};
  },
+ componentDidMount: function() {
+   this.loadCommentsFromServer();
+   setInterval(this.loadCommentsFromServer, this.props.pollInterval);
+ },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

ReactDOM.render(
- <CommentBox url="/api/comments" />,
+ <CommentBox url="/api/comments" pollInterval={2000} />,
  document.getElementById('content')
);

componentDidMount()はコンポーネントが最初にレンダリングされた際に実行されるReactのメソッド。中で独自メソッドのthis.loadCommentsFromServerを呼び出し、データをサーバから取得している。

上のコードの処理の流れは、たぶんこんな感じ。
1. ReactDom.render()でフレームワーク起動、CommentBoxコンポーネントのレンダリング
2. getInitialState()statedata値設定。これはrender内でthis.state.dataと書くことでアクセス可能。
3. componentDidMount()が実行され、サーバからajaxでデータを取得。
4. データが取得できたらthis.setState({data: data});が実行され、statedataプロパティにajaxで取得したデータが挿入され、コンポーネントが再びレンダリング。

実行

ここまで書けばとりあえず動かせるようになるようなので、動かしてみる。
サーバはなんでもいい。自分はnodeサーバを起動。

$ node server.js
Server started: http://localhost:3000/

ブラウザでhttp://localhost:3000/にアクセス。

Hello_React.png

/comments.jsonを更新。

[
    {
        "id": 1388534400000,
        "author": "Pete Hunt",
        "text": "Hey there!"
    },
    {
        "id": 1420070400000,
        "author": "Paul O’Shannessy",
        "text": "React is *great*!"
    }
]

[
    {
        "id": 1388534400000,
        "author": "Pete Hunt",
        "text": "Hey there!"
    },
    {
        "id": 1420070400000,
        "author": "Paul O’Shannessy",
        "text": "React is *great*!"
    },
    {
        "id": 9999999999999,
        "author": "ABCDEFG",
        "text": "あいうえお"
    }
]

Hello_React.png

リアルタイムで更新された。

(2)おしまい。(3)に続く。