Wizard Notes

Pythonを使った音楽信号分析の技術録、作曲活動に関する雑記

React+Python Flask:数値入力フォームのデータをPOSTで送信するWebアプリ例

Flask と React でWebアプリを設計する練習として、フォームからPOSTでデータを送信/受信する簡単なWebアプリを作成してみました。

フォルダ/ディレクトリ構成

(アプリ用フォルダ)
├─ static
│ └─ main.jsx
├─ templates
│ └─ index.html
└─ app.py

実行方法(ローカル)

まず、アプリ用フォルダをカレントディレクトリとして、PythonのFlaskローカルサーバを動かします。

>python app.py

その後、適当なブラウザで http://localhost/ にアクセスしてください。

実行例

まず、アプリを実行すると↓のような画面になります。

f:id:Kurene:20210801234624p:plain

+,-ボタンを押すと、中央の数字がそれぞれ -1, +1 されます。

その後 Submit を押すとその数値がFlaskサーバにPOSTされます。

今回はテストなので、Flaskサーバの応答として送信したデータをそのまま返して alertで表示しています。

f:id:Kurene:20210801234653p:plain

プログラム

Python Flask (app.py)

今回は簡単な例として、POSTで送られてきた数値をそのまま返すような応答としています。

# -*- coding: utf-8 -*-
from flask import Flask
from flask import render_template, request, jsonify
from pprint import pprint


app = Flask(__name__)

@app.route('/', methods = ['POST', 'GET'])
def index():
    if request.method == 'POST':
        result = request.get_json()
        pprint(result)
        return jsonify({"test_post": f"OK: {result}"})
      
    return render_template('index.html')

      
if __name__ == "__main__":
    app.run("0.0.0.0", 80, debug=True)

JavaScript (main.jsx)

fetchを使ってPOSTし、正常な応答であれば中身をalertで表示します。

class ReactPostExample extends React.Component {
  state = {
    value: 0,
  }

  constructor() {
    super();
    
    this.increment = this.increment.bind(this);
    this.decrement = this.decrement.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  
  get value() { return this.state.value; }

  increment() {
    const { max } = this.props;
    if (typeof max === 'number' && this.value >= max) return;
    this.setState({ value: this.value + 1 });
  }

  decrement() {
    const { min } = this.props;
    if (typeof min === 'number' && this.value <= min) return;
    this.setState({ value: this.value - 1 });
  }
    
  handleSubmit = async () => {
    const response = await fetch("/", {
        method: "POST",
        headers: {'Content-Type' : 'application/json'},
        body: JSON.stringify(this.value)
    })
    if (response.ok) { 
        let json = await response.json();
        alert(json["test_post"])
    }
    else {
        alert("HTTP-Error: " + response.status);
    }
  }
  
  render = () => {
    return (
      <div className="input-bpm" style={this.props.style}>
        <button type="button" onClick={this.decrement}>&minus;</button>
        <span> {this.value} </span>
        <button type="button" onClick={this.increment}>&#43;</button>
        <p><button type="button" onClick={this.handleSubmit}>Submit</button></p>
      </div>
    )
  }
}

ReactDOM.render(
  <div>
    <ReactPostExample min={-10} max={10} />
  </div>, 
  document.getElementById('root')
)

HTML (index.html)

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Cache-Control" content="no-cache">
    <title>ReactPostExample</title>

    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>

  <body>
    <div id="root"></div>
    
    <script type="text/babel" src="static/main.jsx" defer></script>
  </body>
</html>