兵どもが、夢のあとさき

JavaScript 系の言語に興味を惹かれ、まったりと更新しております

Python その2 何でもいいのでプログラムをとりえあず、作成する(やっぱり Hello World!! ?)

photo from an airplane(JAL) above cloud.

先程Pythonをインストールした際に、IDLE(統合開発環境)も同時にインストールされています。今後はこれを使ってプログラミングしていきたいと思います。
IDLEとは、対話型のテキストエディタです。見た目は Windows の Power Shell と言った感じでしょうか。特徴として、

  • ロスプラットホーム Windows, Linux, macOS で動作します
  • コード入力、出力、エラーメッセージの色付け機能を持った Python shell (対話的インタプリタ) ウィンドウ
  • 多段 Undo(やり直し機能ですね)、 Python 対応の色づけ(定型句を別の色に変化させたりとか)、自動的な字下げ、呼び出し情報の表示、自動補完(長いコマンドを入力するのは面倒ですよね? それを一覧を表示して選択できるようにしてくれます)等、多機能なマルチウィンドウ・テキストエディタ
  • 任意のウィンドウ内での検索、エディタウィンドウ内での置換、複数ファイルを跨いだ検索 (grep)
  • 永続的なブレイクポイント、ステップ実行(1行ずつ実行させることができます)、グローバルとローカル名前空間の視覚化機能(変数のスコープとか意外と厄介なんですよね)を持ったデバッガ

が挙げられます。IDLEは「Integrated DeveLopment Environment」の略とも言われていますが、開発者の名前から取った説も有力です。IDE(統合開発環境:同じやん!)はよく聞かれますが、'L' が無理やり入っているのがPythonの開発環境の特徴ですね。
ぶっちゃけどうでも良い話ですが。

さて、起動します。IDLEを起動します。IDLE(休眠)だけに。

スタートボタンから、IDLE (Python 3.12 64-bit) 赤で囲まれた部分をクリック。

すると、こんな感じでIDLEが立ち上がります(いやー、使いづらそう…)。
好みですけれど PythonIDE統合開発環境)は、IDLEのみでは無いので自分の手に合った環境を使い続けるのがベストかなとは感じます。私的には、Visual Studio Code が好きですね。好きと言うか手になじんだと言うべきか。プログラム自体はエディタがあれば書けるので、Notepad++ (各言語毎に対応)でも良いですし、Unix系でしたら vim でゴリゴリ書かれている人もいるかもしれません。

とりあえず、Hello World!! だけ表示させてみます。
IDLEのコマンドプロンプト上で、
 print("Hello World!!")
と打ち込んでください。そして、enter キー押下。

以上です。
ちなみに、p と打ち込んで tab キーを押すと p から始まるコマンド群の一覧がずらっと表示されます(p の前後のアルファベットで始まるコマンドも表示されます)。print とすべて打ち込まなくても、そこから選ぶ方が楽ですし、打ちミスも無くなりますね。

以上は、コマンドプロンプト上で実行した Python のプログラムですので、一度きりです。実際にはプログラムを記載して、それを Pythonインタプリタ(コマンドを翻訳して実行してくれるプログラム?)で実行する形になります。その際にエディタは必須となるわけですが、これを IDLE を使用しても良いですし、他のエディタを利用して記述して、Pythonインタプリタで実行すればOKです。

では、次はエディタで簡単なプログラムを記述して Pythonインタプリタに実行させてみましょう。

いきなりPython

24/03/03(日)から頑張ります。Pythonの基礎から応用まで分かり易く、でも深層までしっかり踏み込んでいくよ。

photo from JAL airplane above Chitose City.

 

インストール

 何はともあれインストールですね。私の場合Windows上で諸々行っておりますので、次のURLを叩いて、Pythonをダウンロードします。

www.python.org

https://www.python.org/downloads/windows/

Pythonのダウンロード画面

ダウンロード画面

2024/03/02 現在の latest(最新)版は、3.12.2 ですね。クリックすると、下記画面となります。

 私の環境に合致した、Windows installer (64-bit)を選択します。軽い、Windows embeddable package (64-bit) もありますが、他のパッケージを手動で入れなければならない等の手間がありますので、こちらは上級者になってから手を付けた方が良さそうです。Windows installer (64-bit) は、recommended ともありますし。


「Add python.exe to PATH」のチェックも入れましょう。

「Install Now」をクリック。

上記の様に「Setup was successful」と表示されればOKです。
「Close」をクリックしてインストールは終了です。

 

Reactって何だー(JSX、props編)

photo at Rebun island

JSXとは

 JSX とはなんでしょうか。JSX とは、JavaScript + XML の略で、JavaScript の拡張構文です。UI がどのような見た目かを記述するために、React で JSX を使用することは必須と言って良いでしょう。基本的な形式は、

function コンポーネント名(引数) {
 /*
  JavaScript

 */

 return (
  HTML文
 )
}

となります。

 それでは、簡単な JSX 構文のプログラムを作成してみましょう。プロジェクト名は jsx としましょう。

 ターミナルを立ち上げ、react フォルダに戻ります。ここで、\react> npx create-react-app jsx でプロジェクトを作成します。しばらく、コーヒータイムです。

VSCode で、「フォルダを開く」で jsx フォルダを選択して開きます。下記の画面になります。(publicフォルダと、srcフォルダは展開しました)

ここで App.js を開きます。

 これが、JSX の雛型です。
 コンポーネントを作成します。(6~8行目、呼び出しは25行目)

結果は、

の様に、’Hello!!’ がコンソールに表示されました。

props を使用して引数をコンポーネントに渡す

 次の様に、プログラムを変更します。(6 及び 25行目)

 props というオブジェクトで引数を受け取っています。25行目で name='Hello!!' を渡していますので、受け側は、props.name という形でそのデータを受け取ることができます。props に渡す変数は、文字列、数字、関数、コンポーネント、オブジェクト何でも引き渡すことが可能です。複数の引数を渡したい場合には、下記の様に呼び出し側をスペースで区切ってください。

 一点注意ですが、props は親コンポーネントから、子コンポーネントへ渡される引数であり、逆はありません。また、props という名称は、特に決まった名称ではなく、hikisuu でも hennsuu でも何でも構いませんが、ただ、React では props という名称を使うことが慣例となっていますので、可読性を考慮した場合、props を使用することが良いでしょう(なお、props は properties の略で、財産、資産という意味です)。

 また、今更になりますがコンポーネントの名称の頭文字は必ず大文字にして下さい。<hello /> では認識されません。function hello() も同様です。

 

 

Reactって何だー(ソフトウェア開発編 その2)

photo at Moiwa mountain

 

 おはようございます。暑い日が続いてますね。皆さま熱中症には十分注意してください。それでは早速続きと参りましょう。

Axiosの使い方

 前ページで、Axios の使い方が間違っていると記載しましたが、本来の Axios は以下の様な記述をする必要があります(今回は get メソッド)。

 

axios.get(URLを記述)
 .then(function(response) {
        // getが成功した時の処理
        console.log(response)
    })
   .catch(function(error) {
       // getが失敗した時の処理
       console.log(error)
    })
    .finally(function() {
      // axiosの処理結果によらずいつも実行させたい処理を記述
    })

 

 それでは実際に実装してみましょう。そして成功時、失敗時の時の処理の動きを確認しましょう。

15~26行目を書き換えました。実行してみると、

 以前同様、宗谷地方の気象情報を得ることができました。それでは、次はエラーを発生させてみましょう。URL を書き換えます。

 存在しないエリア番号を指定しましょう。結果は、

 エラーコード 404 (Not Found)が出力されています。つまり存在しないファイルということですね。これをデバッガではなく UI 上に出力させるためコードを下記の様に書き換えました。

 
import logo from './logo.svg';
import './App.css';
import axios from "axios";  // npm install axios を実施済

function App() {

  const weatherData = 'みんなの天気予報'
  var obj = ''

  const Req = async () => {

    // const area = "011000"   // 宗谷地方
    const area = "000000"   // 何処?

    await axios.get(url + area + ".json")
      .then(function(response) {
        // get処理の成功時
        // console.log(response)
        obj = response.data[0].timeSeries[0].areas[0].area.name
        + ": "
        + response.data[0].timeSeries[0].areas[0].weathers[0];

      // alert(obj)
      document.getElementById('weather').textContent = obj

      })
      .catch(function(error) {
        // 処理の失敗
        console.log(error)
        if(error.response) {
          document.getElementById('weather').textContent = 'エラーが発生しました'
          + ': ' + error.config.url
          + ': ' + error.response.status
        }
      })
      .finally(function() {
        // 成功時も、失敗時も実行される
      })
 
    }

  const buttonAlert = () => {
    // alert(JSON.stringify({weatherData})); // コメントアウトしました
    Req()
  }

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <div id='weather'>
          <p>{weatherData}</p>
        </div>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
        </a>
        <div><button onClick={buttonAlert}> {weatherData} </button></div>
      </header>
    </div>
  );
}

export default App

 これでエラーステータス 404 が表示されるかと実行すると、

 エラーステータスが、0 となってしまいます。これでは、エラーハンドリングを行うことができません(デバッガでも、error.response.status は、0 でした)。エラーハンドリングは非常に重要性が高く、トラブルが発生した際にエンドユーザに現在何が発生しているのかを通知(回線障害、サーバ障害、不正処理等々)するために必要なものです。従って、ここの部分(エラーハンドリング)で手を抜くと運用に入った際にトラブルシューティングに非常に時間を要する可能性があります。

 しかし、困ったな… 悩んでいても仕方がないのでここは一度ペンディングします。取得方法が判明したら改めてご報告したいと思います。

 

コンポーネント化について

 これまで App.js にすべてのソースを書いてきました。小さなプログラムですからこれで問題はないのですが、様々な機能を一つのファイルにすべて詰め込むとバグが出た際にデバッグが困難になったり、先だっても述べましたがフッタの様に複数のプログラムで同様の機能を各々作成していてはメンテナンス性も悪くなります。

 React は元々コンポーネント化を考慮された言語であり、部品と呼ばれるコンポーネントを組み合わせることにより、より簡易な構築そしてメンテナンス性の高いプログラムが書けるようになっています。それでは、App.js をコンポーネント化していきます。

import logo from './logo.svg';
import './App.css';
import axios from "axios";  // npm install axios を実施済

function App() {

  const weatherData = 'みんなの天気予報'
  var obj = ''

  const Req = async () => {

    const area = "011000"   // 宗谷地方
    // const area = "000000"   // 何処?

    await axios.get(url + area + ".json")
      .then(function(response) {
        // get処理の成功時
        // console.log(response)
        obj = response.data[0].timeSeries[0].areas[0].area.name
        + ": "
        + response.data[0].timeSeries[0].areas[0].weathers[0];

      // alert(obj)
      document.getElementById('weather').textContent = obj

      })
      .catch(function(error) {
        // 処理の失敗
        console.log(error)
        if(error.response) {
          document.getElementById('weather').textContent = 'エラーが発生しました'
          + ': ' + error.config.url
          + ': ' + error.response.status
        }
      })
      .finally(function() {
        // 成功時も、失敗時も実行される
      })
 
    }

  const buttonAlert = () => {
    // alert(JSON.stringify({weatherData})); // コメントアウトしました
    Req()
  }

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <div id='weather'>
          <p>{weatherData}</p>
        </div>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
        </a>
        <div><button onClick={buttonAlert}> {weatherData} </button></div>
      </header>
    </div>
  );
}

export default App

 現在の App.js プログラムです。この中で、Req 関数を呼び出しています。この部分をコンポーネント化してみます。

 まず Req 関数の部分を選択し、切り取ります(ctrl + x)。
 次に、下向き鏃の src を選択し、「新しいファイルの作成」(ctrl + n)を実行。

 この画面で「言語の選択」をクリック。「言語モードの選択」に react と入力します。

 JavaScript React をクリック。

 先ほどのソースをペースト(ctrl + v)

 「ファイル(F)」から、「名前を付けて保存」を選択し、Req と名称をつけて保存してください。

 src フォルダのやや下の方に、Req.jsx*1 というファイルが生成されました。
 生成されたファイルの内容は以下の通りです。(不要なコメントを外したり、obj 変数を関数内に入れてあります)

const Req = async () => {

  const area = "011000"   // 宗谷地方
  var obj = ''

  await axios.get(url + area + ".json")
    .then(function(response) {
      // get処理の成功時
      // console.log(response)
      obj = response.data[0].timeSeries[0].areas[0].area.name
      + ": "
      + response.data[0].timeSeries[0].areas[0].weathers[0];

    document.getElementById('weather').textContent = obj

    })
    .catch(function(error) {
      // 処理の失敗
      console.log(error)
      if(error.response) {
        document.getElementById('weather').textContent = 'エラーが発生しました'
        + ': ' + error.config.url
        + ': ' + error.response.status
      }
    })
    .finally(function() {
      // 成功時も、失敗時も実行される
    })
  }

 そして、元の App.js からは Req() に相当する部分を削除して下さい。ソースは下記となります。

import logo from './logo.svg';
import './App.css';
import axios from "axios";  // npm install axios を実施済

function App() {

  const weatherData = 'みんなの天気予報'
  const buttonAlert = () => {
    // alert(JSON.stringify({weatherData})); // コメントアウトしました
    Req()
  }

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <div id='weather'>
          <p>{weatherData}</p>
        </div>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
        </a>
        <div><button onClick={buttonAlert}> {weatherData} </button></div>
      </header>
    </div>
  );
}

export default App

 

 さて結果は?

 エラーとなりました。Req() 関数が見つからないようです。

 実はコンポーネントは明示的に自分自身を外へ開示する必要があります。そして読み込む方も、そのコンポーネントを明示的に読み込む必要があります。具体的には、

Req.jsx には

export default Req

と記述する必要があり、読み込む側の App.js には

import Req from './Req';

を記述する必要があります。export は最終行に、import は頭に記述することになっています(単なる慣例ですけど)。

 もう一つ大事な点があります。Axios ライブラリの読み込みに関してです。Req() 関数をコンポーネント化しましたので、Axios は App.js ではなく Req.jsx で読み込む必要があります。そこで、App.js の

 
import axios from "axios";

を削除して、Req.jsx の頭に張り付けてください。

 実行します。と言うか React は勝手にコンパイルされるのでエラーが出ていた場合には、本章を再度読み直して確認してください。

 この画面になっていればOKです。ボタンをクリックすると、

 はい、元の挙動どおりに稼働しました。これがコンポーネント化です。

 

引数の引き渡し

 一応コンポーネント化は行われましたが、これでは何がおいしいのかメリットが見当たりません。そこで次は、Req コンポーネントに引数を渡して(そうですね、宗谷地方以外の地域も表示できるようにして)みましょう。引数を渡すことによって、Req コンポーネントの使いまわしが可能となります。

 まず、親コンポーネントである App.js を下記の様にReq メソッドに引数を指定します。

function App() {

  const weatherData = 'みんなの天気予報'
  var area = ''
  var areaName = ''

  const buttonAlert = () => {
    Req(area = '011000', areaName = '北海道')
  }
 
 

 次に、Req.jsx メソッドが引数を受け取る様に書き換えます。

const Req = async (area, areaName) => {


  await axios.get(url + area + ".json")
    .then(function(response) {
      // get処理の成功時
      let obj = areaName + "の" + response.data[0].timeSeries[0].areas[0].area.name
      + ": "
      + response.data[0].timeSeries[0].areas[0].weathers[0];

        document.getElementById('weather').textContent = obj
    })

 結果は、

 この様に引数が引き渡されました。

 これを複数の地域の情報を表示させます。App.js を次のように書き換えてみましょう。(変更部分のみ)

App.js

  const buttonAlert = () => {
    Req(area = '471000', areaName = '沖縄地方')
    Req(area = '350000', areaName = '山口県')
    Req(area = '330000', areaName = '中国地方')
    Req(area = '270000', areaName = '大阪府')
    Req(area = '230000', areaName = '中部地方')
    Req(area = '130000', areaName = '東京都')
    Req(area = '020000', areaName = '青森県')
    Req(area = '016000', areaName = '札幌')
    Req(area = '012000', areaName = '北海道中部')
  }

Req.jsx

  await axios.get(url + area + ".json")
    .then(function(response) {
      // get処理の成功時
      let obj = areaName + "の" + response.data[0].timeSeries[0].areas[0].area.name
        + ": "
        + response.data[0].timeSeries[0].areas[0].weathers[0];

        // document.getElementById('weather').textContent = obj

        var c = document.getElementById('weather');
        c.insertAdjacentHTML('afterbegin', "<li align='left'>" + obj + "</li>");

    })

 結果は、

の様になりました。
 ただ、Req.jsx を複数呼び出しているのはみっともないので連想配列を使って、シンプル化します。
 App.js

 この様に、連想配列を使用することにより、ソースの見通しが良くなりました。コメント部分は不要なので削除してしまいましょう。

 App.js

import './App.css';
import Req from './Req';

function App() {

  const weatherData = 'みんなの天気予報'

  let areaData = {'012000': '北海道中部', '016000': '札幌', '020000': '青森県', '070000': '福島県',
                  '130000': '首都', '230000': '中部地方', '270000': '近畿地方', '330000': '中国地方',  
                  '350000': '山口県', '471000': '沖縄地方',
    }

  const buttonAlert = () => {    
   
    Object.keys(areaData).forEach(key => {
      Req(key, areaData[key])
    })
  }

  return (
    <div className="App">
      <header className="App-header">
        <div id='weather'>
          <p>{weatherData}</p>
        </div>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
        </a>
        <div><button onClick={buttonAlert}> {weatherData} </button></div>
      </header>
    </div>
  );
}

export default App

 Req.jsx

import axios from "axios";

const Req = async (area, areaName) => {


  await axios.get(url + area + ".json")
    .then(function(response) {
      // get処理の成功時
      let obj = areaName + ": " + response.data[0].timeSeries[0].areas[0].area.name
        + ": "
        + response.data[0].timeSeries[0].areas[0].weathers[0];

        var c = document.getElementById('weather');
        c.insertAdjacentHTML('beforeend', "<li align='left'>" + obj + "</li>");
      })

    .catch(function(error) {
      // 処理の失敗
      console.log(error)
      if(error.response) {
        document.getElementById('weather').textContent = 'エラーが発生しました'
        + ': ' + error.config.url
        + ': ' + error.response.status
      }
    })

    .finally(function() {
      // 成功時も、失敗時も実行される
    })
}

export default Req

 結果は?

 結果は表示されましたが、地方の順序がばらばらです。やはり、北から or 南から表示させたいですね。連想配列は通常の配列と異なり、順不同で格納されています。そのため、取り出す際に登録した順には得ることができないのです。

 連想配列で順番を保ちたい場合には Map オブジェクトを使用するとうまくいきます。

App.js

import './App.css';
import Req from './Req';

function App() {

  const weatherData = 'みんなの天気予報'

  const buttonAlert = () => {
   
    const areaData = new Map([
      ['012000', '北海道中部'], ['016000', '札幌']    , ['020000', '青森県'],
      ['070000', '福島県']    , ['130000', '首都']    , ['230000', '愛知県'],
      ['270000', '近畿地方']  , ['280000', '兵庫県']  , ['330000', '中国地方'],
      ['350000', '山口県']    , ['471000', '沖縄地方'],
    ])
 
    Req(areaData)

 }

  return (
    <div className="App">
      <header className="App-header">
        <div id='weather'></div>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
        </a>
        <div><button onClick={buttonAlert}> {weatherData} </button></div>
      </header>
    </div>
  );
}

export default App

 連想配列を Map で定義し、そのオブジェクトをまるごと Req.jsx に引数として渡します。

Req.jsx

import axios from "axios";

const Req = async (areaData) => {

  for (let [key, areaName] of areaData) {
 
    const obj = url + key + ".json"

    await axios.get(obj)

      .then(function(response) {
      // get処理の成功時
      let obj = areaName + ": " + response.data[0].timeSeries[0].areas[0].area.name
        + ": "
        + response.data[0].timeSeries[0].areas[0].weathers[0];

        let pattern = / /ug
        obj = obj.replace(pattern, '')

        let c = document.getElementById('weather');
        c.insertAdjacentHTML('afterend', "<li align='left'>" + obj + "</li>");
      })

      .catch(function(error) {
      // 処理の失敗
        console.log(error)
        if(error.response) {
          document.getElementById('weather').textContent = 'エラーが発生しました'
          + ': ' + error.config.url
          + ': ' + error.response.status
        }
      })

      .finally(function() {
        // 成功時も、失敗時も実行される
      })
    }
}

export default Req

 あとは、Req.jsx で、そのオブジェクトを受け取り、for で各要素を処理していきます。ついでに、正規表現を使用して

 let pattern = / /ug
 obj = obj.replace(pattern, '')

で余計な全角スペースを削っています。さて結果は、

 見事に、南から北への天気予報が表示されました。余計なスペースも削られて、見やすくなっていますね。
 この章はここまでです。次章では、React の肝である JSX と props を使用したコンポーネントを作成していきたいと思います。

 

 

 

 

 

*2

 デフォルトでは、React DOM は JSX に埋め込まれた値をレンダー前にエスケープします。このため、自分のアプリケーションで明示的に書かれたものではないあらゆるコードは、注入できないことが保証されます。レンダーの前に全てが文字列に変換されます。これは XSS (cross-site-scripting) 攻撃の防止に役立ちます。

 

JSX の導入 – React より引用。これにより、同時にクロスサイトリクエストフォージェリ (CSRF) を防ぐことも可能となります。

 
 

MongoDB などの NoSQL データベースでは JSON と同様のフォーマットのデータをそのまま格納することができます。

*1:Reactは、JavaScriptと明確に異なることを明示するために、.jsx という拡張子を付けることが慣例となっています

*2:Axiosのセキュリティについて

*3:今後使いたいDBについて

Reactって何だー(Material-UI の使い方)

 

shogorobe.hatenablog.com

photo in Sapporo city (You may see a rainbow?)

 

インストール

 ユーザインタフェースって結構見た目も重要ですよね。そこで、CSS を変更したり、かっこいいバック画像をはめ込んでみたりを行うわけですが、デザインのセンスが皆無の私には、その部分の敷居が非常に高く感じてしまうわけです。

 そこで、ここではユーザインタフェースを簡単に実装できてしまうライブラリをご紹介します。それが、Material-UI です。

続きを読む

Reactって何だー(ソフトウェア開発編 その1)

photo in Kyoto city

 さて、"Hello World!!" の表示は行うことができたので、次に簡単なプログラムを作成してみましょう。お題は、友人のいる地域の天気予報一覧です。
私は、とあるスマホゲームをやっておりオフ会等を行ってきた結果(最近はコロナの影響でできませんが…)全国に友人を増やすことができました。最近(2022/07/11現在)は気温も高くなり、コロナの他にも熱中症にも気を使うことも多く、その話題でチャットが盛り上がったりします。
 そこで、今回は全国各地にいる友人の地域の天気予報(現在の気温、湿度等も含む)を一覧にして表示するプログラムを作成することにしました。

 

 天気予報の情報は、気象庁JSON 形式で提供していますので、こちらを使用させていただきます。(気象庁の情報を利用するためには利用規約があります。使用する場合にはこちらを十分留意してください。)

 

 

 早速とりかかるとします。今回のプロジェクト名は "weather" 、構築環境は VSCode を使用します。まず、コマンドプロンプト/ターミナルでプロジェクトを作成します。
 

例によって数分かかります。今日は暑いのでアイスコーヒーを作って飲んで待ってます

完了しました。では次に VSCode で本プロジェクトを開きます。

 

 

本プロジェクトの流れは、下記のようになります。

 

(1) ユーザがボタンを押す

(2) 気象庁のサイトから気象情報を JSON 形式で取得

(3) 予め設定した地域の情報を選択

(4) HTML 形式で出力

となります。いたってシンプルですね。

 

ここで一点言い訳弁明を。react ではコンポーネントと呼ばれる小さな部品を組み上げてソフトウェアを作成することが推奨されています。これは、前回も述べたように小さな部品を構成することにより、変更点が生じた場合最小限の労力で、修正することができるからです。しかし、ここでは手を抜いて前回の "Hello World!!" で使用した、App() コンポーネントにすべて入れ込むことにしました。初学者は細かいことを考えるよりガンガン手を動かして、ソフトウェアをガンガン作成していきましょう!

 

と言うことで、App() コンポーネントに必要なソースを書いていきます。

App.js を開きます。デフォルトでは下記の様になっています。

ユーザがボタンを押す

 ユーザがボタンを押すためには、そのボタンを表示させなければなりません。では、ボタンを表示させます。20行目に下記を記載して下さい。

        <div><button> みんなの天気予報 </button></div>

 これは JSX でも何でもなく、単なる HTML ですね。しかし、とりあえずボタンらしいものは表記されるようになりました。

このボタンは押しても何も起こりません。それは当然です。ボタンを押したときのイベント処理に対するソースを何も記載していませんから。

 では次に、その処理のソースを記載しましょう。ただし、JSON の取得部分のソースもまだですので、何か別の変化が起こる様にしましょう。例えば、よくあるポップアップにしましょうか。

 

一応の説明をしておくと、JSX は return 文で DOM(HTML)を返します。従って、return 文の中に変数定義を記述することはできません。

例えば、JSX では、変数の定義に const を使用しますが、

 const weatherData = 'みんなの天気予報'

を return 文の中に記載してしまうと(20行目)、

 

下記の結果になります。

ですので、JSX で変数定義等を行う場合には、return 文の外に記載する必要があります。書き換えてみましょう。

6行目の return 文の外に、変数を定義しました。そして13行目に {weatherData} と記述しました。結果は?

の様に、6行目で定義した weatherData という変数の内容が、13行目の {weatherData} によって正常に表記されています。

 ※重要なことを記載していませんでした。JSX で定義した変数を、return 文内で使用する場合には、{  } で括って下さい。そうでないと変数名そのままが表記されてしまいます。

 前置きが長くなりました。それでは、ボタンクリックイベントを作成しましょう。

 イベントが発生した時の関数を作成しましょう。ポップアップでいいので、alert 文を使用します。前述のとおり、return 文の外(今回は前)で定義します。ついでに <button> タグにも、その関数を呼び出す様に JSX を記載します。

8~10、26行目に注目してください。

 関数定義 const buttonAlert = () => {  は独特の表記ですが、今は雰囲気だけ味わっておいて下さい。そのうち () 内に props とか入り始めますから。

8~10行 は関数定義、26行は button タグに、その関数を呼び出す様に記述しました。しつこい様ですが、return 内で JSX の関数名や変数名を使用する場合には、{  } で括ることを忘れないで下さい。b

では実行。ボタンをクリック!

あれ? 何ですかこの [object Object] とは?

ググるとー。JSON.stringify(変数名) で内容が取得できるらしい。では、

おおー。要するに連想配列(react だと何て言うんでしょう? => 連想配列でいいらしい。javascript だから当然ですか)だから key と data に分ければ良いようです。まあここは本質では無いのでこのまま放置します。(JSON.stringify(変数名) 関数はブラウザ依存なのであまり使用しない方が良いですね。今回は chrome を使用)
とりあえず、ボタンイベントが完成したので次へ進みます。

 

気象庁のサイトから気象情報を JSON 形式で取得

 とりあえず、気象庁のサイトをブラウザで叩いてみるとこうなります。

JSON データの羅列が取得できます。でも凄まじい量ですね。これを毎度毎度取得するのもリソースの無駄ですし、何といっても気象庁のサイトに負担をかけてしまいます。そこで、まず東京のみの情報を取得してみたいと思います。

https://www.jma.go.jp/bosai/forecast/data/forecast/130000.json

これをブラウザで叩いてみてください。

ほうほう、東京都の情報が得られました。しかも、天気予報や気温などの情報も含まれているではないですか。

これを JSX から取得するには、Axios というライブラリを使用します。それでは実際に実装してみます。

Axios を使用するには、まず axios ライブラリを import する必要があります。下記の3行目。

すると、

エラーとなります。どうやら、Axios ライブラリはデフォルトでは実装されていないようです。ここで取る手段は2つ。npm を使用してライブラリをインポートするか、CDNを使用して外部からライブラリを引き込むかの二択です。Axios 自体は軽いライブラリですので(94k程度)npm を使用してインポートします。

下記を実行します。

 npm install axios(npm i axios という省略形もあります)

完了しました。

CDN を使用する場合には、/pubic/index.html の <body> タグ内に

<script type="text/babel">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" />
 

の様に 記載すればOKです。

 

さて、では Axios を実装していきましょう。

3行目で、Axios ライブラリをインポートしています。

9~14行目が、気象庁のデータにアクセスし、console.log で結果を出力する Req() 関数定義となります。axios.get() 関数でシンプルに HTTP の GET メソッドで気象庁JSON 情報を取得します。

※ console.log はデバッガに結果を出力するメソッドなので、実行前に console.clear で内容をクリアしています

18行目で Req() を呼び出します。

さて結果は?

ボタンを押しても何も変化は無いと思います。前述のとおり、console.log は画面上ではなく、デバッガに結果を出力するメソッドすので画面上には出力されません。ここで、デバッガを立ち上げます。ctrl + shift + I (i です、愛)すると、

デバッガが立ち上がります。デバッガの、上部にある console タブをクリックして下さい。

status は、HTTP のレスポンス状態を示しています。200 ですから正常に取得できていますね。では次に、取得したデータを見てみましょう。「▶ {data: ~ の ▶ をクリック」=> 「▶ {request: ~ の ▶ をクリック」=> 「」。responseText という項目がありますので、カーソルをそこにフォーカスすると、東京都全域の情報がテキスト表示されます。

これは、つまり気象庁が提供している JSON データを response 変数に格納されたことを意味します。デバッガでは、その内容を確認できた訳ですね。

response 変数に JSON データが格納されたことは確認できましたが、次にこの内容を展開して UI 上に表示する必要があります。それでは response 変数の展開を行っていきます。

 

<余談>

 コンポーネントの呼び出し方ですが、これまで App() の様に関数であるかのような表記を使ってきました。しかし jacascript では様々な呼び出し方があり、例えば下記の様な表記方法もあります。18行目を参照してください。

呼び出し方は様々です。本来は統一した方がデバッグも行いやすいと考えますが、人の書いたコードをメンテしたりする際に、色々な手法を知っておかないと困ることもありますので、「あーこんな表記方法もあるんだな」程度で良いと思いますので学んでおいて損は無いと思います。他にも import と require の関係など枚挙にいとまがありません。

</余談>

予め設定した地域の情報を選択

 まずは単純に気象庁JSON データにどの様な情報が含まれているのか、それをブラウザ上でわかりやすい表記を行えるようにしましょう。と、その前に VSCode 上で成形して見やすくしてみましょう。再度、気象庁のサイトをブラウザで叩いてみてください。JSON データがずらりと表記されます。これをすべてコピーしてください(全選択 ctrl + a して ctrl + c)。ここで VSCode へ戻り、「新規ファイル」=> 「新しいテキスト ファイル」(ctrl + n でもOKです)から新規ファイルを開きます。

テキスト内に、「言語の選択」とありますので、そこをクリック

「言語モードの選択」という入力画面が表示されますので、JSON と入力。

「{ } Json (json)」をクリック。

この画面に戻りますので、先ほどコピーした JSON データを貼り付け(ctrl + v)。

こんな感じで、一行にペーストされました。ここで、shift + alt + f と打ってください。

この様に可読性の良いフォーマットで JSON データが表示されます。ちなみに、このデータの頭は(テキストの適当な部分をクリックして、)、

 この様に北から情報が取得できることが分かると思います。"centers" タグは中央管区の情報を包括(のちほど別のタグも出没します)を表し、"name" 及び "enName" はそのエリア名、"officeName" は各エリアの管区気象台の日本語表記、"childlen" はその名の通り、そのエリアがどこの地域を統括しているかということ(ここでは単なる数字表記ですが)が何となく分かると思います。

fig.1

 さてここで、行数を示す箇所にカーソルを移動させると、下向きの鏃の様なマークが表記されます。2行目もそうですね。下向きということは、ここではすべての情報が展開されていることを意味しています。ここで、2行目の鏃をクリックしてみてください。

fig.2

"centers" タグが折りたたまり、139行目から始まる "offices" タグ情報が表記されました。ここで注視していただきたいのが、fig.1(唐突に図番を入れました)と、fig.2 の比較です。fig.2 では140行目にタグの無い、"011000" 表記があります。そして fig.1 では、8行目に同様に "011000" と記載されています。これはつまり、"centers" の "children" である "011000" の情報が、"offices" に書かれていると言うことを表してみます。つまり、

の配下に、

        "011000": {
            "name": "宗谷地方",
            "enName": "Soya",
            "officeName": "稚内地方気象台",
            "parent": "010100",
            "children": [
                "011000"
            ]
        },

この様に、宗谷地方が含まれていることが分かると思います*1

 

 と、ここまで来ましたが実はこのデータは各地域(行政区とは異なるかな?)のコード(さきほど確認した "011000" のことですね)を確認するために取得したものです。実は天気予報の JSON 情報は別にありまして、

 https://www.jma.go.jp/bosai/forecast/data/forecast/xxxxxx.json(xxxxxx が先ほど取得した地域コード)が実際の天気予報の情報となります。それでは、せっかく宗谷地方のコードが判明しましたので、そちらの天気予報を見てみましょう。

 https://www.jma.go.jp/bosai/forecast/data/forecast/011000.json

をブラウザで叩いてみてください。

 これを先ほどの手順で VSCode に張り付けて成形すると

 この様に、宗谷地方の天気予報らしき情報を得ることができました。これは使えそうですね。(東京の情報を取得するつもりが、宗谷地方になっていますけれど…)

 

 かなり話が外れてしまいましたが、それでは Axois を実装して宗谷地方の情報を取得してみましょう。

11行目から、16行目までが変更点です。実行し、デバッガを立ち上げます。そして適当に展開してみると、

 今日(2022/07/23現在)の宗谷地方は少し天気が悪そうです。
 さて、それでは各個別の情報を取得していきましょう。JSON入れ子になっており、多段化されていることが多いです。気象台のデータもかなり入り組んでいますね。そこで必要な要素のみを取得してみましょう。まず、地域コード "011000" の地名を取得します。下記の要領で展開して(一部展開を戻しました)、name が地域名となりますが相当深い位置にありますね。これを手繰るのは大変なので、name へカーソルを持っていき、右クリックすると下記のメニューが表示されます。ここで「Copy property path」を選択。パスがクリップボードに読み込まれます。これは後ほど使用します。

さて、VSCode に戻ります。

18行目に alert(response) と書き込み、実行してみると、

この様になります。これは以前も発生した現象ですね。つまり、内容が Object なので、そのままでは表示されないわけです。

そこで、コードを下記の様に書き換えて下さい。



18行目の「data[0].timeSeries[0].areas[0].area.name」とは何ぞや、と思われたかと。実はこれが先ほどクリップボードに読み込んでおいた、JSONname のパスに相当します。この様に深いネストでも、デバッガの「Copy property path」から読み取り、貼り付け(ctrl + v)で簡単に対応することができるわけです。実行してみると、

 この様に、地域コード "011000" の地名を取得することができました。天気予報も同時に表示したければ、下記の様に + で連結すれば表記されます。

alert に出力ばかりしても意味がありませんから、画面遷移を使って表示させてみます。

25行目、id 'root' 全体を書き換えました。

一応表示されました。ただ、画面遷移するのは気持ち悪いのでもう少し手を入れます。App.js の46 ~ 48行目に新たに、<div id='weather'>を差し込みます。

そして、

obj 変数内のコンテキストを、先ほどの id = 'weather' に差し込みます。さて結果は?

上図の様に、画面遷移無しに宗谷地方の気象情報が表示されました(2022/07/24現在)。

 

実はこのソースかなり適当に書かれています。悪いお手本の様なソースですね。JSX ライクな書き方ではありませんし、Axiosも正しく使用されていません(エラーハンドリング等)。それでは、次のページでは Axios の正しい使い方や、JSX ライクな記述法、最終目標である友人たちのエリアの天気予報を完成させたいと思っております。では。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

私が参照した、遅延勉強法の動画です。これ、私知らず知らずのうちにやってました。

www.youtube.com

 

*1:JSON に関しては、こちらのサイトの方が非常に分かり易く書かれていますので、ぜひ一度チェックなさってください