React


Fetching from the server


コンポーネントの構造は


javascript

var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function (comment) {
      return (
        <Comment author={comment.author}>
          {comment.text}
        </Comment>
      );
    });
    return (
      <div className="commentList">
        {commentNodes}
      </div>
    );
  }
});

var CommentForm = React.createClass({
  render: function() {
    return (
      <div className="commentForm">
        Hello, world! I am a CommentForm.
      </div>
    );
  }
});

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>
    );
  }
});

var Comment = React.createClass({
  render: function() {
    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML= />
      </div>
    );
  }
});

React.render(
  <CommentBox url="../comments.json" pollInterval={2000} />, 
  document.getElementById('content')
);

 読み込むファイルをurlで指定

React.render(
  <CommentBox url="../comments.json" />, 
  document.getElementById('content')
);

このコンポーネントはこれまでのコンポ―ネットとは違い、コンポーネント自身を再描画する必要があります。 サーバーへのリクエストが戻ってくるまでは、このコンポーネントにはデータがありません、戻ってきた時点でコンポーネントはコメントを描画する必要があるのです。

Reactive state

これまでは、属性を元に、コンポーネントは1度しか描画されませんでした。属性は不変であり:親コンポ―ントから渡され、親によって所有されています。相互のやり取りを実行するには、コンポーネントに変更可能な状態を持たせる必要があります。 this.state はプライベートであり、 this.setState()  を呼ぶことで変更できます。 状態が更新されると、コンポーネントは自身を再描画します。

render() メソッドは this.props と this.state の関数として宣言され書かれています。 このフレームワークは入力値に対してUIは常に矛盾が起こらないことを保証しています。

サーバーからデータをとってくると、すでにあるコメントデータの変更が起きます。 コメントデータの配列をCommentBoxコンポーネントに加えると、その状態は

var CommentBox = React.createClass({
  getInitialState: function() {
    return {data: []};
  },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});
getInitialState()は、コンポーネントが存在している間に1度だけ実行され、初期状態を設定します

Updating state

コンポーネントが生成されたら、サーバーから JSONを取ってきて、最新のデータを反映させたいですね。 実際のアプリケーションの場合、これは動的に最終データまで持ってくることになりますが、この例では静的なjsonファイルを使ことで簡単にします。

[
  {"author": "Pete Hunt", "text": "This is one comment"},
  {"author": "Jordan Walke", "text": "This is *another* comment"}
]

サーバーに対する非同期リクエストを生成するのにjQueryを使います

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

componentDidMount メソッドは、コンポーネントが描画されると、Reactによって自動的に呼び出されます。 動的に更新するときのキーとなるのは、 this.setState() に対して、このメッソドを呼ぶことです。 サーバーから来た新しいコメントで古いコメントを置き換え、自動でUIも更新されます。

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>
    );
  }
});

React.render(
  <CommentBox url="comments.json" pollInterval={2000} />,
  document.getElementById('content')
);

ここで行ったことは、 AJAX呼び出しを別のメソッドに移し、コンポーネントが最初に読み込まれた時とそのあと2秒ごとに呼び出すようにしたことです。 ブラウザの実行中にJSONファイルを変更すると、2秒以内に変更が反映されます。