maesblog

React.jsチュートリアル【日本語翻訳】

フロントエンドの世界では今React.jsが注目されてきていて、自分もチュートリアルをやる機会があって、その際に日本語訳(和訳)を簡単に作っていました。まだこのチュートリアルに関して翻訳されたものがなさそうだったので、ちょっと手直ししてブログにアップすることにしました。誤訳などもあるかと思いますが、Google翻訳よりはマシだと思ってお使いいただければと思います。

当記事のチュートリアルは「React v0.13」当時の古い内容のものとなっています。最新の「React」の公式チュートリアルの翻訳記事は以下となります。

React.js

react.js(リアクト)
React.js

ReactはFacebookが開発しているJavaScriptのフレームワークです。MVCで言う所のViewの部分に特化したフレームワークとなっています。特徴はComponent単位で作るUI、VirtualDOM、一方向性を保ったデータの流れだったりします。詳細は、公式サイトをご確認ください。

チュートリアル


以下、チュートリアルの日本語訳となります。
(頭では理解できていても言葉で表現するのが難しかったりして誤訳などもあるかと思いますので、おかしな部分があったら上記の本家のチュートリアリルも確認していただけたらと思います。また、間違いなどありましたら正解と一緒にお知らせいただけると幸いです。)

追記(2015年3月11日): 2015年3月10日にReact.jsのバージョンが0.13.0にアップデートされました。それに伴いチュートリアルにも変更がありましたので内容を更新しました。
追記(2015年5月1日): 2015年4月18日にReact.jsのバージョンが0.13.2にアップデートされました。それに伴いチュートリアルにも若干変更がありましたので内容を更新しました。
追記(2015年5月17日): 2015年5月8日にReact.jsのバージョンが0.13.3にアップデートされました。それに伴いチュートリアルにも若干変更がありましたので内容を更新しました。
※変更された部分は色をつけてわかるようにしてあります。

チュートリアル(日本語訳)

シンプルですが実用的なブログ向けのコメントボックスを作っていきます。Disqus、LiveFyre、Facebookのコメントでも使われているリアルタイムコメント機能のベーシック版となります。

実装する機能:

  • コメントの全てのビュー
  • コメントを送信するためのフォーム
  • カスタムバックエンドを提供するためのフック

いくつかの特徴:

  • 軽快なコメンティング: コメントはサーバーに保存される前にリストに表示されるので高速に感じます。
  • ライブアップデート: 他のユーザーのコメントがリアルタイムでコメントビューにひょいと出てきます。
  • Markdown形式: ユーザーはテキストをフォーマットするためにMarkdownを使えます。

すべてスキップして、今すぐソースをみたいですか?

すべてはGitHubにあります

サーバーを動かす

このチュートリアルで開始する必要はないにしても、後になると起動しているサーバーへのPOSTingを要求する機能を追加することになります。もしサーバーに精通していて自分のサーバーを作りたい方であれば、そうしてください。サーバーサイド側に関して気にすることなく、Reactの学習に集中したいという人のために、いくつかの言語-JavaScript(Node.js)、Python、ruby、Go、PHPでシンプルなサーバーを用意しています。それらは全てGitHubで利用可能です。ソースを見るか、スタートするのに必要な全てを含んでいるzipファイルをダウンロードしてください。

チュートリアルを開始するために、public/index.htmlの編集をスタートしましょう!

スタートしよう

このチュートリアルではCDN上の既存のJavaScriptファイルを使っていきます。好きなエディタを開いて、新しいHTMLドキュメントを作りましょう:

<!-- index.html -->
<html>
  <head>
    <title>Hello React</title>
    <script src="https://fb.me/react-0.13.3.js"></script>
    <script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
    <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/jsx">
      // Your code here
    </script>
  </body>
</html>
Code

このチュートリアルでは、最後までこのScriptタグの中にJavaScriptのコードを書いていきます。

注意:
Ajaxの処理を書く部分をシンプルにするためにjQueryをインクルードしていますが、Reactを動かすために必須とはなっていません。

はじめてのコンポーネント

Reactはモジュラー、構成可能(コンポーザブル)なコンポーネントが全てです。コメントボックスの例では、以下のような構造のコンポーネントを使っていきます:

- CommentBox  - CommentList   - Comment  - CommentForm

CommentBoxコンポーネント(シンプルな<div>)を作りましょう:

// tutorial1.js
var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});
React.render(
  <CommentBox />,
  document.getElementById('content')
);
Code

ネイティブなHTML要素は頭文字が小文字となりますが、ReactのカスタムClassは頭文字が大文字となるということに気をつけてください。

JSX構文

まず最初にJavaScriptの中にあるXML-ishの構文に気付くでしょう。糖衣構文(シンタックスシュガー)を素のJavaScriptに変換するシンプルなプリコンパイラがあります:

// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
  render: function() {
    return (
      React.createElement('div', {className: "commentBox"},
        "Hello, world! I am a CommentBox."
      )
    );
  }
});
React.render(
  React.createElement(CommentBox, null),
  document.getElementById('content')
);
Code

使用することは任意となりますが、JSX構文は素のJavaScriptよりも簡単に扱えます。詳細はJSX構文に関する記事を読むとよいでしょう。

何が起きているのか

新しいReactコンポーネントを作るために、JavaScriptのオブジェクトの中のメソッドをReact.createClass()に渡しています。その中でも最も重要なメソッドは「render」です。renderは、最終的にHTMLにレンダリングされるReactコンポーネントのツリーを返す役割を担っています。

使われている<div>タグは、現実のDOMノードではありません。それらはReactのdivコンポーネントがインスタンス化されたものです。つまりReactがどう扱うか知っているデータのマーカーやその一片のようなものとして考えることができます。Reactは安全です。HTML文字列を生成していないため、最初からXSS対策がなされています。

ベーシックなHTMLを返さなくてよく、自分(または他者)が作ったコンポーネントのツリーを返せます。これがReactをコンポーザブルにしています。それはメンテナブルなフロントエンドとして重要な信念でもあります。

React.render()は、ルートコンポーネントをインスタンス化し、フレームワーク(構成)を開始し、マークアップを生のDOM要素(2番目の引数として渡される)へ注入します。

コンポーネントを作る

CommentListCommentFormのためのスケルトンを作りましょう。それらは再度シンプルな<div>タグで作れます:

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

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

次に、新しいコンポーネントを扱うためにCommentBoxコンポーネントをアップデートしましょう:

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

どのようにHTMLのタグと作ったコンポーネントを混合して書いているか見てください。HTMLコンポーネントは、1つの違いはあるものの、あなたが定義するコンポーネントと同じように正規のReactコンポーネントです。JSXのコンパイラは自動的にHTMLタグをReact.createElement(tagName) という形式で書き換えて、それ以外の部分はそのままにしておきます。これはグローバルの名前空間の汚染を防ぐためです。

propsを使う

Commentコンポーネントを作りましょう。子コンポーネントは親からのデータに依存することになります。親コンポーネントから渡されたデータは、子コンポーネント上で「プロパティ」として利用することができます。これらの「プロパティ」はthis.propsを通してアクセスされます。propsを使うことで、CommentListからCommentに渡されたデータを読むことができ、マークアップをレンダリングできるようになります:

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

(「属性」か「子要素」かのどちらかとして)JSXの中でJavaScriptのコードを波括弧で囲むことによって、テキストやReactコンポーネントをツリーの中に落とし込むことができます。this.propsのkeyを通してコンポーネントに渡された名前の付けられた属性と、this.props.cildrenを通してネストされた要素にアクセスします。

コンポーネントのプロパティ

Commentコンポーネントを定義しました。ユーザー名とコメントのテキストをCommentコンポーネントに渡したくなるでしょう。Commentコンポーネントを定義しておくことで、それぞれのコメントごとに同じコードを使い回すことができるようになります。さあ、いくつかのコメントをCommentListの中に追加しましょう:

// tutorial5.js
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>
    );
  }
});
Code

親のCommentListコンポーネントから子のCommentコンポーネントにいくつかのデータを渡したということに注意してください。例えば、Pete Hunt(属性を通して)とThis is one comment(XMLのような子ノードを通して)を一番目のCommentに渡しました。親から子コンポーネントに渡されたデータはprops(propertiesを省略して)と呼びます。上記の通り、Commentコンポーネントはthis.props.authorthis.props.childrenを通してこれらの「プロパティ」にアクセスします。

Markdownを追加する

Markdown記法はインラインのテキストをフォーマットする簡単な方法です。例えば、強調させたい場合は、アスタリスクと一緒にテキストを囲みます。

まず、サードパーティーのライブラリmarked.jsをあなたのアプリケーションに追加しましょう。これはMarkdownテキストを受け取り、生のHTMLにコンバートしてくれるJavaScriptのライブラリです。head内にscriptタグを使って追加します。:

<!-- index.html -->
<head>
  <title>Hello React</title>
  <script src="https://fb.me/react-0.13.3.js"></script>
  <script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
  <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
</head>
Code

次にコメントのテキストをMarkdownにコンバートし、アウトプットしてみましょう:

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

ここで行っていることはmarkedライブラリの呼び出しです。this.props.childrenを、Reactのラップされたテキストから、生の文字列(markedが解釈することになる)にコンバートする必要があるので、明示的にtoString()を呼ぶようにします。

しかし、ここに問題があります。レンダリングされたコメントはブラウザに以下のような感じで表示されてしまいます。
<p>This is <em>another</em> comment</p>“.
実際はこれらのタグをHTMLとしてレンダリングしないといけません。

このようにしてReactはXSS攻撃からあなたを守っています。これをうまく回避する方法もありますが、フレームワークは使用してはいけないと警告を出します:

// tutorial7.js
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={{__html: rawMarkup}} />
      </div>
    );
  }
});
Code

これは生のHTMLの挿入を意図的に難しくさせる特殊なAPIですが、markedのためにこのバックドアのアドバンテージを使います。この場合、「sanitize: true」を渡すことで、markedにソース内のどんなHTMLのマークアップでも変化しない状態で渡すことがないようエスケープするように伝えています。

備忘: この機能を使うということは、安全性をmarkedに依存しているということを忘れないでください。

データモデルをつなぐ

ここまでは、ソースコードの中に直接コメントを挿入することを行ってきました。次は、JSONデータをコメント一覧の中にレンダリングすることを行ってみましょう。最終的にサーバーから取得することになりますが、まずは自分のソースの中に書いていきます:

// tutorial8.js
var data = [
  {author: "Pete Hunt", text: "This is one comment"},
  {author: "Jordan Walke", text: "This is *another* comment"}
];
Code

このデータをモジュール式の方法で(一つの塊として)CommentListの中に取り込む必要があります。CommentBoxReact.render()の呼び出しを修正して、propsを通してこのデータをCommentListの中に渡せるようにしましょう:

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

React.render(
  <CommentBox data={data} />,
  document.getElementById('content')
);
Code

これでデータはCommentListの中で使えるようになるので、コメントを動的にレンダリングしましょう:

// tutorial10.js
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>
    );
  }
});
Code

そうです!

サーバから取ってくる

上記ではハードコーディングされたデータを使いましたが、サーバーからの動的なデータに置き換えていきましょう。dataプロップを取り除き、フェッチするためのURLに置き換えます:

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

このコンポーネントは以前のコンポーネントとは異なります。なぜならコンポーネント自身を再びレンダリング(re-render)しなければいけなくなるからです。コンポーネントはサーバーからのリクエストが戻ってくるまでどんなデータも持たず、リクエストが戻ってきた時点でコンポーネントは新しいコメントをレンダリングするようになっています。

リアクティブな状態

ここまでは、propsに基づいて、各コンポーネントは自分自身を一回レンダリングしてきました。propsはイミュータブルです:それらは親から渡されるものであり、親によって「所有されているもの」です。親と子の相互作用を実装するために、ミュータブルなstateをコンポーネントに取り込みます。this.stateはコンポーネントに対してプライベートであり、this.setState()を実行することによって変更可能です。stateがアップデートする時、コンポーネントは自分自身を再びレンダリングします。

render()メソッドはthis.porpsthis.stateの関数として宣言的に書かれています。フレームワークは、UIが常にインプットと一致していることを保証しています。

サーバーがデータを取得する時、保持しているコメントデータを変更していることになります。コメントデータの配列をstateとしてCommentBoxコンポーネントに追加してみましょう:

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

getInitialState()はコンポーネントのライフサイクルの間に1回だけ正確に実行され、コンポーネントの初期状態をセットアップします。

stateのアップデート

コンポーネントがまず作られたら、サーバーからのJSONをGETして、最新のデータに反映するためにstateをアップデートするようにします。実際のアプリケーションにおいて、これは動的なエンドポイントとなるでしょう。今回の例では、説明をシンプルにするために静的なJSONファイルを使うことにしています:

// tutorial13.json
[
  {"author": "Pete Hunt", "text": "This is one comment"},
  {"author": "Jordan Walke", "text": "This is *another* comment"}
]
Code

サーバーへの非同期のリクエストを楽に行うためにjQueryを使います。

注意: これはAJAXの機能を持ったアプリケーションとなるので、ファイルシステムに置いているファイルを使うよりむしろWebサーバーを使ってアプリを開発することが必要となってきます。上で言及したように、GitHub上でいくつかのサーバーを提供しています。これらのサーバーはこのチュートリアルの後半部分で必要となってくる機能を提供します。

// tutorial13.js
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>
    );
  }
});
Code

さて、componentDidMountはコンポーネントが最初にレンダリングされた後にReactによって自動的に呼ばれるメソッドです。動的な更新のポイントはthis.setState()の呼び出しです。コメントの古い配列をサーバーからの新しい配列に置き換え、UIは自動的に自分自身をアップデートします。このリアクティビティによって、ライブアップデートを追加するための変更は最小で済みます。ここではシンプルなポーリングを使っていますが、簡単にWebSocketsや他の技術を使うこともできます。

// tutorial14.js
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')
);
Code

ここで行ってきたことは、AJAXの呼び出しを独立したメソッドに移動させることと、コンポーネントが最初にロードされ、その後2秒ごとにそれを実行させることです。ブラウザでこれを動かし、comment.jsonファイルを変更してみましょう。2秒以内に変化が見られるでしょう!

新しいコメントを追加する

さて、フォームを作る時がきました。CommentFormコンポーネントはユーザーに名前とコメントのテキストを入力してもらい、そのコメントを保存するためにサーバーへリクエストを送るようにしましょう。

// tutorial15.js
var CommentForm = React.createClass({
  render: function() {
    return (
      <form className="commentForm">
        <input type="text" placeholder="Your name" />
        <input type="text" placeholder="Say something..." />
        <input type="submit" value="Post" />
      </form>
    );
  }
});
Code

フォームを対話式にしてみましょう。ユーザーが送信した時に、それをクリアし、サーバーへリクエストを送信し、コメントのリストをリフレッシュするようにします。始めに、フォームの送信イベントを受け取り、それをクリアしてみましょう。

// tutorial16.js
var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = this.refs.author.getDOMNode().value.trim();
    var text = this.refs.text.getDOMNode().value.trim();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    this.refs.author.getDOMNode().value = '';
    this.refs.text.getDOMNode().value = '';
    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>
    );
  }
});
Code

イベント

Reactはイベントハンドラ(命名規則としてキャメルケースを用います)をコンポーネントに結び付けます。onSubmitハンドラをフォームに設置し、そのフォームはvalidなインプットデータが送信される時にフォームのフィールドをクリアします。

フォーム送信時のブラウザのデフォルトのアクションを防ぐために、イベント上でpreventDefault()を呼びましょう。

Refs

子コンポーネントに名前を割り当てるためにref属性を使い、コンポーネントを参照するためにthis.refsを使います。ネイティブなブラウザのDOM要素を取得するためにコンポーネント上でgetDOMNode()React.findDOMNode(component)を実行させます。

propsとしてのコールバック

ユーザーがコメントを送信する時、新しいコメントを含めるためにコメントのリストをリフレッシュする必要があります。CommentBoxはコメントのリストを表示するstateを所持しているため、CommentBoxでこのロジックの全てを行うことは理にかなっています。

子コンポーネントのバックアップからその親にデータを渡す必要があります。新しいコールバック(handleCommentSubmit) を子に渡し、子のonCommentSubmitイベントにそれをバインドすることによって、親のrenderメソッドの中でこれを行います。イベントがトリガーされるたびに、コールバックは実行されることになります。

// tutorial17.js
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)
    });
  },
  handleCommentSubmit: function(comment) {
    // TODO: submit to the server and refresh the list
  },
  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 onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
});
Code

ユーザーがフォームをサブミットした時に、CommentFormからコールバックを実行してみましょう:

// tutorial18.js
var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    this.refs.author.getDOMNode().value = '';
    this.refs.text.getDOMNode().value = '';
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});
    this.refs.author.getDOMNode().value = '';
    this.refs.text.getDOMNode().value = '';
    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>
    );
  }
});
Code

コールバックが適切に実行されたら、サーバーにサブミットしてリストを更新する必要があります:

// tutorial19.js
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)
    });
  },
  handleCommentSubmit: function(comment) {
    $.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 (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
});
Code

最適化: 快適なアップデート

アプリケーションは今フィーチャーコンプリート(ユーザーが求めている何かの提供を完了させること)状態となっていますが、コメントがリストに表示されるまで、完了のためのリクエストを待たなくてはならないことは遅いと感じるはずです。アプリをより速く感じさせるためにコメントをリストに気軽に追加する方法があります。

// tutorial20.js
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)
    });
  },
  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 (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
});
Code

おめでとう!

いくつかのシンプルなステップを通して、コメントボックスを作りました。なぜReactを使うのかもっと学んでいきましょう。または、APIリファレンスに飛び込んで、ハッキングをスタートさせましょう。幸運を祈ります!


チュートリアルは以上となります。

サンプルを実行して確認する

このチュートリアルのサンプルはGitHubからダウンロードすることができます。手っ取り早くReactがどんなものか見たい場合は、以下より「react-tutorial-master」をダウンロードして動作などを確認されると良いと思います。

サンプルをダウンロードしたら、適当なフォルダに入れてその中に移動します。

$ cd react-tutorial-master

ご自身の環境に合わせてサーバーを起動します。Node.js環境で確認する場合は以下のコマンドを実行します。その他にPythonRubyPHPGoに対応しています。

$ npm install
$ node server.js
[npm install]コマンドでpackage.jsonに記載の依存関係にあるパッケージがインストールされ、[node server.js]コマンドでサーバーを起動します。

ブラウザで「http://localhost:3000」にアクセスします。サンプルはコメントリストになっていて、付属の「comments.json」ファイルに対してデータの読み込みや書き込みが行えるようになっています。

今後の参考に

チュートリアルだけでもそれなりに把握することができますが、オライリーからもついにReactの書籍が出ましたので紹介しておきます。ただしタイトルに「入門」とありますが、はっきり言って入門書ではありません。なので、まずはこちらのチュートリアルをやってある程度把握されてから知識を固めるために読むとよいと思います。

入門 React ―コンポーネントベースのWebフロントエンド開発
  • 『入門 React ―コンポーネントベースのWebフロントエンド開発』
  • 著者: Frankie Bagnardi, Jonathan Beebe, Richard Feldman, Tom Hallett, Simon HØjberg, Karl Mikkelsen, 宮崎 空(翻訳)
  • 出版社: オライリージャパン
  • 発売日: 2015年4月3日
  • ISBN: 978-4873117195

またご存知の方も多いと思いますが、以下もReactを理解する上ですごく助けになりますので紹介しておきます。

追記

最後に翻訳に関してわかりにくい部分などありましたらお知らせいただけると幸いです。@keno_ssさんより以下のようなアドバイスがありました。ありがとうございます。

関連記事

コメント

Comments are closed.