Reactチュートリアル入門: Pythonサーバーサイド連携編

チュートリアル | React がなくなったようで。。良いチュートリアルだったのに。。
まあとりあえず、前回は クライアントサイドのみでWebサイトを表示したので、 今回はサーバーサイドで取得したデータをクライアントサイドに渡して表示させる。 とは言っても、JSONファイルを表示するだけなので、非常に簡単。 ただし、サーバーサイドはNode.jsではなく、Pythonを使う。 その前にまず、前回のReactコードを少しカスタマイズする。

クライアントサイドのカスタマイズ

CommentBox

前回、シンプルだったCommentBoxに色々追記する。

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

Ajax通信を行う。urlは、後ほどReactDOM.renderでCommentBoxに渡される。 これがサーバーサイドへのパスになる。dataはサーバーサイドから返ってきたデータ。  

  getInitialState: function() {
    return {data: []};
  },

クライアントサイドのdataの初期化。dataはObjectのArrayなので[]となる。  

  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },

DOMに関わる初期化。 loadCommentsFromServerで設定したAjaxリクエストや、リフレッシュ頻度を指定するsetIntervalの登録など、 server-side rendering時には必要ない初期化処理についてはこの中で行う。

以上より、今回のCommentBoxは次のようになる。  

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 comments={this.state.data} />
      </div>
    );
  }
});

ReactDOM.render

設定したCommentBoxに、ReactDOM.renderでパラメーターを渡す。 サーバーサイドのパスとなるurlと、リフレッシュ頻度となるpollIntervalを指定する。 前回はurlキーではなく、dataキーにクライアントサイドで定義したdataを渡していた。 pollIntervalは公式では2000(2秒)だが、短すぎるので2000秒としておく。

ReactDOM.render(
  <CommentBox url="/api/comments" pollInterval={2000000} />,
  document.getElementById('content')
);

Pythonサーバーサイド

Pythonのサーバーサイドは、Flaskを使っている。 Flaskは僕も知らないので、ググって下さい。 でもFlaskはまったく悩むことなく簡単に使えるようで、 クライアントサイドで指定したurl='/api/comments' [check1!] のすぐ下のcomments_handler() の中でデータを取得して返している。 今回はGETのみなので、単純にserver.pyと同じディレクトリーに置かれたcommnet.jsonを読み込んで [check2!] 、 json形式にPythonで適切に変形して、クライアントサイドに返している [check3!] ことが分かる。

import json
import os
import time
from flask import Flask, Response, request

app = Flask(__name__, static_url_path='', static_folder='public')
app.add_url_rule('/', 'root', lambda: app.send_static_file('index.html'))  # client and server side with json file

@app.route('/api/comments', methods=['GET', 'POST'])  # Check1!
def comments_handler():
    with open('comments.json', 'r') as f:
        comments = json.loads(f.read())  # Check2!

    if request.method == 'POST':
        new_comment = request.form.to_dict()
        new_comment['id'] = int(time.time() * 1000)
        comments.append(new_comment)

        with open('comments.json', 'w') as f:
            f.write(json.dumps(comments, indent=4, separators=(',', ': ')))

    return Response(
        json.dumps(comments),  # Check3!
        mimetype='application/json',
        headers={
            'Cache-Control': 'no-cache',
            'Access-Control-Allow-Origin': '*'
        }
    )

if __name__ == '__main__':
    app.run(port=int(os.environ.get("PORT", 3000)), debug=True)

実行

$ python server.py

上記のコマンドを実行すると、以下のように表示されるはず。

f:id:Shoto:20161030002637p:plain