【 開発練習 】天候情報を取得するアプリケーション
この資料では、フォームに街の名前を入力してボタンをクリックすると、その街を含む地域の現在の天候情報が取得できるアプリケーションのサンプルコードを紹介します。
このアプリケーションは、天候情報を取得する Web API として「 WeatherAPI 」というサービスを利用します。このサービスを利用するためにはアカウントの登録が必要です。まずは、以下の手順に沿って登録を行ってください。
1. アカウントの登録手順
サービスを利用するためには、アカウント登録後に発行される API Key が必要です。この API Key はアカウント毎に発行されるもので、リクエスト時にURLのクエリパラメータに含めて送信します。
- 以下のURLにブラウザでアクセスする
https://www.weatherapi.com/ - ナビゲーション内の「Signup」をクリックする
- メールアドレスとパスワードを入力して登録する
- 届いた認証メール内のURLをクリックしてアカウントの登録を完了する
- 登録したメールアドレスとパスワードでログインする
- ダッシュボード(Dashboards)で API Key を確認する
2. API Key を使用してリクエストを送信する
天候情報を取得するときは、アカウント登録時に発行された API Key と 街の名前 をクエリパラメータに含めた、以下のURLでリクエストを送信します。
http://api.weatherapi.com/v1/current.json?key=[API Key]&q=[City Name]
このリクエストのレスポンスはJSONです。例えば、東京(Tokyo)の現在の天候情報を取得すると次のようなJSONデータが返ってきます。
{
"location": {
"name": "Tokyo",
"region": "Tokyo",
"country": "Japan",
"lat": 35.69,
"lon": 139.69,
"tz_id": "Asia/Tokyo",
"localtime_epoch": 1702327499,
"localtime": "2023-12-12 5:44"
},
"current": {
"last_updated_epoch": 1702326600,
"last_updated": "2023-12-12 05:30",
"temp_c": 11,
"temp_f": 51.8,
"is_day": 0,
"condition": {
"text": "Light rain shower",
"icon": "//cdn.weatherapi.com/weather/64x64/night/353.png",
"code": 1240
},
"wind_mph": 6.9,
"wind_kph": 11.2,
"wind_degree": 30,
"wind_dir": "NNE",
"pressure_mb": 1011,
"pressure_in": 29.85,
"precip_mm": 1.86,
"precip_in": 0.07,
"humidity": 94,
"cloud": 75,
"feelslike_c": 10.1,
"feelslike_f": 50.2,
"vis_km": 7,
"vis_miles": 4,
"uv": 1,
"gust_mph": 7,
"gust_kph": 11.3
}
}
もし指定した街の名前で天候情報が見つからなかった場合は、"error"
プロパティをもつJSONデータが返ってきます。
{
"error": {
"code": 1006,
"message": "No matching location found."
}
}
3. アプリケーションのサンプルコード
このアプリケーションは次のように、「App」「Form」「Results」の3つのコンポーネントに分割して作成します。まずは、開発用のディレクトリの作成から進めてください。
開発用のディレクトリの作成
はじめに、create-react-app
を使用してアプリケーションの開発に必要なパッケージや設定ファイルを含むディレクトリを作成します。
npx create-react-app weather-app
アプリケーションに不要なファイルを削除して、新しいファイルを追加して下記のような構成にしましょう。
weather-app
|--- node_modules ◀ ここは変更しない
|--- public
| |--- index.html
|
|--- src
| |--- index.js
| |--- App.jsx
| |--- Form.jsx
| |--- Results.jsx
|
|--- .gitignore
|--- package.json
|--- package-lock.json
|--- README.md
メインページとメインプログラムの編集
public ディレクトリにある index.html と srcディレクトリにある index.js は次のように作成してください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Weather App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<h1>World Weather Forecast</h1>
<div id="root">
<!-- このにアプリケーション(Appコンポーネント)を展開する -->
</div>
</body>
</html>
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
App コンポーネントの作成
App コンポーネント(App.jsx) は次のように作成します。App コンポーネント内で作成した状態変数(data
)と状態変数を更新する関数(setData
)をそれぞれ Form コンポーネント と Results コンポーネントに渡すことで、コンポーネント間のデータ連携を行います。この状態変数で取得した天候情報を管理し、情報が更新されると Results コンポーネントに反映される仕組みです。
import { useState } from 'react';
import Form from './Form';
import Results from './Results';
export default function App() {
const [data, setData] = useState(null);
return (
<>
<Form setData={setData} />
<Results data={data} />
</>
);
};
Form コンポーネントの作成
フォームによるリクエスト処理は Form コンポーネントにまとめます。取得したJSONデータから、 Results コンポーネントの展開に必要な情報のみを抽出して、 引数で受け取った setData
関数を利用して、Results コンポーネントに渡されている状態変数 data
を更新します。
import { useState } from 'react';
const API_KEY = '*******'; // ◀ 取得したAPI KEYを設定する
const BASE_URL = 'http://api.weatherapi.com/v1/current.json';
export default function Form({ setData }) {
const [city, setCity] = useState("");
const getWeather = async (event) => {
event.preventDefault();
if (city === "") return;
const url = `${BASE_URL}?key=${API_KEY}&q=${city}`;
// ▼ 本来はtry-catch文で囲む必要がありますが割愛しています
const response = await fetch(url);
if (response.ok) {
const result = await response.json();
// ▼ Resultsコンポーネントで利用するデータのみを抽出
const data = {
error: false,
country: result.location["country"],
region: result.location["region"],
temp: result.current["temp_c"],
condition: result.current.condition["text"],
icon: result.current.condition["icon"]
}
// ▼ 引数に渡された関数を利用して状態変数を更新する
setData(data);
} else {
// ▼ 指定された街の名前で情報が見つからなかった場合も状態変数を更新する
setData({ error: true, city: city });
}
setCity("");
}
return (
<form className="form">
<input id="city" type="text" placeholder="Enter city name."
onChange={(event) => { setCity(event.target.value) }} value={city} />
<input type="submit" value="Get Weather" onClick={getWeather} />
</form>
);
}
Results コンポーネントの作成
Results コンポーネントでは引数に渡された状態変数 data
(中身は Form コンポーネントで取得した天候情報)を利用して要素を展開します。
export default function Results({ data }) {
return (
<div className="result">
{
/* if-else文を用いて戻り値の制御を行うために即時実行関数式を利用 */
(() => {
// ▼ 初期状態では data は null のためここが実行される
if (!data) {
return <p>Enter city name and click "Get Weather". </p>
}
// ▼ Formコンポーネントで指定された街の名前で情報が見つからなかった場合に実行される
else if (data.error) {
return <p className="not-found">{data.city} is not found.</p>
}
// ▼ 天候情報が取得できている場合はこのreturn文が実行される
return (
<>
<p className="country">{data.country}</p>
<p className="region">{data.region}</p>
<p className="temperature">{data.temp + "℃"}</p>
<p className="condition">{data.condition}</p>
<img src={`https:${data.icon}`}
alt={data.condition} />
</>
);
})()
}
</div>
);
}
プログラムを実行して動作を確認する
ターミナルで次のコマンドを実行すると、作成したアプリケーションの動作が確認できます。
npm run start
スタイルを適用する
完成したアプリケーションにスタイルを適用して見た目を整えてみましょう。まずは、src ディレクトリ下に適用するスタイルをまとめたスタイルシートを作成してください。
weather-app
|--- node_modules
|--- public
| |--- index.html
|
|--- src
| |--- index.js
| |--- App.jsx
| |--- Form.jsx
| |--- Results.jsx
| |--- index.css ◀ このファイルを追加する
作成したスタイルシートに、サンプルとして用意した以下のコードを貼り付けて保存します。
html {
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 16px;
}
html * {
padding: 0;
margin: 0;
}
body {
width: 100%;
height: 100%;
background-color: darkcyan;
}
h1 {
font-size: 3rem;
margin: 2rem;
text-align: center;
color: whitesmoke;
}
.form {
text-align: center;
font-size: 1.5rem;
margin: 1rem;
}
.form input[type=text] {
padding: 0.5rem;
border: none;
border-radius: 5px;
box-shadow: 3px 3px 3px gray;
}
.form input[type=submit] {
padding: 0.5rem;
margin-left: 0.5rem;
border: none;
border-radius: 5px;
color: darkcyan;
font-weight: bold;
background-color: lightcyan;
box-shadow: 3px 3px 3px gray;
}
.result {
background-color: whitesmoke;
text-align: center;
}
.result :first-child {
padding-top: 1rem;
}
.result :last-child {
padding-bottom: 1rem;
}
.result .country {
color: gray;
font-size: 0.8rem;
}
.result .region {
font-size: 1rem;
}
.result .temperature {
font-size: 2rem;
line-height: 4rem;
color: darkcyan;
}
.result .condition {
font-size: 0.8rem;
}
.result .not-found {
color: gray;
padding: 1rem 0;
font-size: 1rem;
このスタイルシートをインポートします。 src ディレクトリにある index.js に次の import
文を追加してください。
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css'; // ◀ このimport文を追加してスタイルシートを読み込む
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
サンプルのスタイルを適用すると、画面が次のように表示されます。
4. アプリケーションをビルドする
このアプリケーションをサーバーにデプロイしたい場合は、先にビルドを行います。 create-react-app
で開発環境を構築した場合は、次のコマンドをターミナルで実行するだけで簡単にビルドできます。
※ ビルドする前にターミナルで「Ctrl + C」を入力して、サーバーを停止させてください。また、コマンドの実行前に開発環境のディレクトリがカレントディレクトリになっていることを確認してください。
npm run build
ビルドが完了すると、次のように build ディレクトリが自動的に作成されます。このディレクトリをそのまま、Netlify のようなホスティングサービスにアップロードするだけで、React のアプリケーションをデプロイすることができます。