React Tutorial　ポイントまとめ


Reactの公式ドキュメントのチュートリアルの軽い翻訳と内容のポイントをまとめています。
引用: 
React 
・Getting Started
http://facebook.github.io/react/docs/getting-started.html
・Tutorial
http://facebook.github.io/react/docs/tutorial.html
・ソースコードon Github
https://github.com/reactjs/react-tutorial

# Hello World
``` helloworld.html
<!DOCTYPE html>
<html>
  <head>
    <script src="build/react.js"></script>
    <script src="build/JSXTransformer.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/jsx">
      React.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
  </body>
</html>
```

- Javascript内に書かれたHTMLタグは「JSX」と呼ばれています
- scriptのtypeは"text/jsx"
- React.renderでJSXと描画先のDOMを指定する。JSXの内容が展開されて描画される

##ファイル分割
``` helloworld.html
<script type="text/jsx" src="src/helloworld.js"></script>
```
- scriptのtypeは"text/jsx"

## オフライン変換
JSXから生のJSへ変換する方法

- インストール方法

``` console
npm install -g react-tools
```

 - 実行方法

指定したディレクトリ内のファイルに変更があった時に毎回生成されます

```　console
jsx --watch ソースディレクトリ
```

# チュートリアル
いわゆるTODOリスト
・ソースコードon Github　https://github.com/reactjs/react-tutorial

``` tutorial3.js
var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList />
        <CommentForm />
      </div>
    );
  }
});

React.render(
  <CommentBox />,
  document.getElementById('content')
);
```
- Reactコンポーネントを作成する時はReact.createClass()。renderで描画。
- React.renderは、ツリーとなっているコンポーネントの場合は一番上のコンポーネントを描画させればいい


```tutorial4.js
var Comment = React.createClass({
  render: function() {
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        {this.props.children}
      </div>
    );
  }
});

var CommentList = React.createClass({
  render: function() {
    return (
      <div className="commentList">
        <Comment author="Pete Hunt">This is one comment</Comment>
        <Comment author="Jordan Walke">This is *another* comment</Comment>
      </div>
    );
  }
});
```
- 親コンポーネントから子コンポーネントへ値を渡す時はthis.propを使用
- this.prop.childrenはタグ内の内容を渡す

## マークダウンの使用
テキストにマークダウンを使用したいときの方法

- マークダウンのライブラリを読み込む

```
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
```
- マークダウンでのテキストを変換させるためにmarked関数を使用。this.props.childrenのままではReactオブジェクトなのでtoStringで文字列へ変換。
- このままだとXSS対策でHTMLタグがそのまま表示されるので、dangerouslySetInnerHTMLを使用する。

```
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
```

## サーバーから非同期にデータを読み込む

```
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')
);
```

- コンポーネントの値を動的に変更する場合はstateを使用する。
- getInitialStateは初期状態のstateを定義する。非同期でサーバーからレスポンスが返ってくる前の状態を定義。
- componentDidMountはコンポーネントが描画されたときに実行される。親から受け取ったurlへjQueryのajaxを使用してデータを問い合わせ。
- レスポンスが返ってきたらsetStateを使用してstateを更新する。setStateをしようすると再描画が行なわれる。
- SetIntervalを使用して、数秒ごとに再描画を行なわせている

## コメントの動的追加
```tutorial16.js
var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});
```
- formのonSubmitでhandleSumbitを実行。handleSubmit内で入力されている値を消す
- inputのDOMのrefに名前をつけ、React.findDomModeでコンポーネント内のDOMを探索。
- プロパティのonCommentSubmitを実行して親コンポーネントへのコールバックを行なう

```
var CommentBox = React.createClass({

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

...

});
```
- 親コンポーネントでサーバーへPOSTし、リストを再読み込みする
- サーバーへPOSTする前にリストへ反映させて描画させることで、ユーザーに体感で早く感じさせる