Reactまとめ - QUICK START - ②

[前回](http://qiita.com/masashi0127/items/ce9d02ac909f3e6e0b1e)の続き
- [Tutrial - Reactive state](http://facebook.github.io/react/docs/tutorial.html#reactive-state)


#Tutrial
- 各コンポーネントに含まれる`props`は不変要素であり、各コンポーネントは`props`を使って自身をレンダリングする。
- `getInitialState()`はコンポーネントのライフサイクル中に一度だけ実行される関数で、コンポーネントの初期化を行う。
- `componentDidMount()`はコンポーネントがレンダリングされる際、Reactにより自動的にコールされる。
- `this.setState()`は、自身の`this.state`変数を更新することで、変化する状態をコンポーネントに反映する（コンポーネント自身を再レンダリングする）。
- ajaxでサーバーからデータを取得するたびに、コンポーネントは再レンダリングされ、UIが更新される。

```js:JS_and_JSX
var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      success: function(data) {
        //サーバーから取得したデータをstateにセットし、再レンダリング
        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();
    // 2000ミリ秒間隔でサーバーからデータを取得
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (
      React.createElement(
        'div',
        {className: 'commentBox'},
        React.createElement('h1', {}, 'Comments'),
        React.createElement(CommentList, {data: this.state.data}),
        React.createElement(CommentForm)
      )

      /* JSX
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
      */
    );
  }
});

React.render(
  // ajax用のurlとsetInterval用の変数をプロパティにセット
  React.createElement(CommentBox, {url: 'url_for_ajax', pollInterval: 2000}),
  document.getElementById('content')

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

- Reactはコンポーネントにイベントハンドラを紐づける。その際のハンドラ名の命名規則はキャメルケース(camelCase)
- `preventDefault()`はフォームアクションを無効化できる。
- `ref`属性にコンポーネント名をセットして、`this.refs`から値を取得できる。
- `getDOMNode()`を使用してブラウザ用のDOM要素を取得できる。

```js:JS_and_JSX
var Comment = React.createClass({
  render: function() {
    return (
      React.createElement(
        'div',
        {className: 'comment'},
        React.createElement(
          'h2',
          {className: 'commentAuthor'},
          this.props.author
        ),
        this.props.children
      )

      /* JSX
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        {this.props.children}
      </div>
      */
    );
  }
});

var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function (comment) {
      return (
        React.createElement(Comment, {author: comment.author}, comment.text)
      )
    });
    return (
      React.createElement(
        'div',
        {className: 'commentList'},
        commentNodes
      )
    );

    /* JSX
    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({
  handleSubmit: function(e) {
    e.preventDefault(); //フォームのactionを無効化
    //参照用のコンポーネント名からDOMを取得し、value値を取得
    var author = this.refs.author.getDOMNode().value.trim();
    var text = this.refs.text.getDOMNode().value.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text}); //CommentBoxのhandleCommentSubmit()をコール
    this.refs.author.getDOMNode().value = '';
    this.refs.text.getDOMNode().value = '';
    return;
  },
  render: function() {
    return (
      React.createElement(
        'form',
        //actionはpreventDefault()により無効化
        {className: 'commentForm', onSubmit: this.handleSubmit, action: 'http://google.co.jp'},
        //refは参照用のコンポーネント名
        React.createElement('input', {type: 'text', placeholder: 'Your name', ref: 'author'}), 
        React.createElement('input', {type: 'text', placeholder: 'YSay something...', ref: 'text'}),
        React.createElement('input', {type: 'submit', value: 'Post'})
      )

      /* JSX
      <form className="commentForm" onSubmit={this.handleSubmit} action="http://google.co.jp">
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
      */
    );
  }
});

var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  handleCommentSubmit: function(comment) {
    //リクエスト処理に時間がかかる場合、先にリストに表示しておく
    var comments = this.state.data;
    var newComments = comments.concat([comment]);
    this.setState({data: newComments});
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      type: 'POST',
      data: comment,
      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 (
      React.createElement(
        'div',
        {className: 'commentBox'},
        React.createElement('h1', {}, 'Comments'),
        React.createElement(CommentList, {data: this.state.data}),
        React.createElement(CommentForm, {onCommentSubmit: this.handleCommentSubmit})
      )

      /* JSX
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
      */
    );
  }
});

React.render(
  React.createElement(CommentBox, {url: 'your.ajax.url', pollInterval: 2000}),
  document.getElementById('content')

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

#次回
- [Thinking in React](http://facebook.github.io/react/docs/thinking-in-react.html)

# 参考
[React](http://facebook.github.io/react/index.html)
[React (Virtual) DOM Terminology](https://gist.github.com/sebmarkbage/fcb1b6ab493b0c77d589#react-elements)