Help us understand the problem. What is going on with this article?

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

More than 3 years have 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)に続く。

saekis
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away