4日目のゴールと今日やること
4日目のテーマは
「API 通信の“中身”はそのままに、UI と使い勝手を一段レベルアップさせる」
ことです。
1〜3日目で、あなたはすでに
fetch と async/await で API からデータを取る
try-catch と response.ok、data.error でエラーを分岐する
ローディング表示とボタン制御を入れる
forecast API で複数日の天気を表示する
という「API 通信アプリの骨格」を手に入れました。
4日目は、この骨格を崩さずに、
天気アイコンの表示
摂氏 / 華氏の切り替え
エラー時の UI の見やすさ
ローディング表示の質を上げる
といった“プロダクト寄りの仕上げ”をしていきます。
今日の完成イメージを先に描く
どんなアプリにしたいか
昨日までのアプリは、
「文字だけで 3 日分の天気を表示する」ものでした。
今日のゴールは、こうです。
都市名を入力して検索
3 日分の天気が「アイコン付き」で表示される
気温を「℃ / ℉」で切り替えられる
ローディング中はスピナー風の表示
エラー時は赤字でわかりやすく表示
つまり、
ロジックはほぼそのままに、
見た目と体験を一段階上げるのが今日のテーマです。
fetch と async/await の「骨格」は変えない
まずは昨日までの基本形を再確認する
API 通信部分は、すでに良い形になっています。
非同期関数であることを示す async
fetch の完了を待つ await
try-catch-finally で成功・失敗・後片付けを分ける
response.ok と data.error でエラーを分岐する
この「型」は、今日もそのまま使います。
例として、3 日分の天気を取る関数はこうでした。
async function fetchForecast(city) {
const error = validateCity(city);
if (error) {
showError(error);
clearResult();
return;
}
startLoading();
try {
const url = buildUrl(city, 3);
const response = await fetch(url);
if (!response.ok) {
showError(`サーバーエラーが発生しました。(${response.status})`);
return;
}
const data = await response.json();
if (data.error) {
showError(`エラー:${data.error.message}`);
return;
}
showStatus("3日分の天気を取得しました。");
renderForecast(data);
} catch (error) {
showError("通信に失敗しました。ネットワークを確認してください。");
console.error(error);
} finally {
endLoading();
}
}
JavaScriptここで大事なのは、
「fetch の書き方はもう変えなくていい」
という感覚を持つことです。
今日やるのは、
この周りにある UI 部分を育てていくことです。
天気アイコンを表示して「情報を一瞬で伝える」
WeatherAPI のアイコン URL をどう使うか
forecast のレスポンスには、
各日の condition.icon というプロパティがあります。
例として、1 日分の JSON はこうです。
{
"date": "2026-01-27",
"day": {
"maxtemp_c": 28.0,
"mintemp_c": 20.0,
"condition": {
"text": "晴れ",
"icon": "//cdn.weatherapi.com/weather/64x64/day/113.png"
}
}
}
icon は「スキーマ省略 URL」になっているので、
実際には “https:” を付けて使います。
renderForecast にアイコンを組み込む
昨日の renderForecast を、
アイコン付きに書き換えます。
function renderForecast(data) {
const name = data.location.name;
const country = data.location.country;
const days = data.forecast.forecastday;
let html = "";
html += `<p>${name} (${country}) の 3 日間の天気</p>`;
days.forEach((day) => {
const date = day.date;
const max = day.day.maxtemp_c;
const min = day.day.mintemp_c;
const text = day.day.condition.text;
const iconUrl = "https:" + day.day.condition.icon;
html += `
<div class="day">
<p>日付:${date}</p>
<img src="${iconUrl}" alt="${text}" />
<p>最高:${max} ℃ / 最低:${min} ℃</p>
<p>天気:${text}</p>
</div>
`;
});
resultDiv.innerHTML = html;
}
JavaScriptこれだけで、
「文字だけの天気」から
「一目でわかる天気」に変わります。
深掘りポイント
ここでやっていることは、
実はとてもシンプルです。
API のレスポンスから
必要な値を取り出す
HTML に埋め込む
fetch や async/await の部分は一切変えていません。
変わっているのは「JSON のどのプロパティを使うか」だけです。
摂氏 / 華氏の切り替えを実装してみる
どこで「単位」を決めるか
WeatherAPI は、
摂氏(temp_c)と華氏(temp_f)の両方を返してくれます。
設計としては、
「どの単位で表示するか」を
アプリ側の状態として持つのが自然です。
例えば、こういう変数を用意します。
let unit = "c"; // "c" or "f"
JavaScriptボタンやセレクトボックスで切り替えられるようにします。
<button id="unitC">℃</button>
<button id="unitF">℉</button>
JavaScript 側でこう書きます。
const unitCButton = document.getElementById("unitC");
const unitFButton = document.getElementById("unitF");
unitCButton.addEventListener("click", () => {
unit = "c";
rerenderIfDataExists();
});
unitFButton.addEventListener("click", () => {
unit = "f";
rerenderIfDataExists();
});
JavaScriptここでのポイントは、
「単位を変えたときに API を再取得しない」
ことです。
すでに取得済みの data を
別の見せ方で表示し直すだけで十分です。
renderForecast を「単位対応」にする
let lastData = null;
function renderForecast(data) {
lastData = data;
const name = data.location.name;
const country = data.location.country;
const days = data.forecast.forecastday;
let html = "";
html += `<p>${name} (${country}) の 3 日間の天気</p>`;
days.forEach((day) => {
const date = day.date;
const max = unit === "c" ? day.day.maxtemp_c : day.day.maxtemp_f;
const min = unit === "c" ? day.day.mintemp_c : day.day.mintemp_f;
const text = day.day.condition.text;
const iconUrl = "https:" + day.day.condition.icon;
const unitLabel = unit === "c" ? "℃" : "℉";
html += `
<div class="day">
<p>日付:${date}</p>
<img src="${iconUrl}" alt="${text}" />
<p>最高:${max} ${unitLabel} / 最低:${min} ${unitLabel}</p>
<p>天気:${text}</p>
</div>
`;
});
resultDiv.innerHTML = html;
}
function rerenderIfDataExists() {
if (lastData) {
renderForecast(lastData);
}
}
JavaScript深掘りポイント
ここで重要なのは、
「API 通信の結果(data)を一度保存しておく」
という発想です。
lastData に保存しておけば、
単位切り替え
表示形式の変更
フィルタリング
などを、
API を叩き直さずに実現できます。
これは「API 通信」と「表示ロジック」を分離する
中級者らしい設計です。
エラーハンドリングを「UI として」整える
エラーをただの文字列で終わらせない
今までは、
statusDiv.textContent に
エラーメッセージを入れていました。
これを少しだけ UI 寄りにします。
例えば、
エラーのときは赤字、
成功のときは緑、
ローディング中はグレー、
というように色を変えます。
.status {
margin-top: 8px;
}
.status.loading {
color: #555;
}
.status.success {
color: #0a0;
}
.status.error {
color: #c00;
}
JavaScript 側でクラスを切り替えます。
function setStatus(message, type) {
statusDiv.textContent = message;
statusDiv.className = "status " + type; // type: "loading" | "success" | "error"
}
function showError(message) {
setStatus(message, "error");
}
function showStatus(message) {
setStatus(message, "success");
}
function showLoading() {
setStatus("天気情報を取得中です…", "loading");
}
JavaScriptfetchForecast の中では、
こう書き換えられます。
async function fetchForecast(city) {
const error = validateCity(city);
if (error) {
showError(error);
clearResult();
return;
}
showLoading();
startLoading(); // ボタン無効化など
try {
const url = buildUrl(city, 3);
const response = await fetch(url);
if (!response.ok) {
showError(`サーバーエラーが発生しました。(${response.status})`);
return;
}
const data = await response.json();
if (data.error) {
showError(`エラー:${data.error.message}`);
return;
}
showStatus("3日分の天気を取得しました。");
renderForecast(data);
} catch (error) {
showError("通信に失敗しました。ネットワークを確認してください。");
console.error(error);
} finally {
endLoading();
}
}
JavaScript深掘りポイント
ここでやっているのは、
「エラーを“状態”として扱う」
ということです。
成功
失敗
ローディング
を、
文字列だけでなく
CSS クラスとしても表現することで、
ユーザーにとって直感的な UI になります。
ローディング表示を「ただの文字」から一歩進める
シンプルなスピナー風表示
CSS で簡単なスピナーを作ることもできますが、
まずは「ローディング中だけ表示される要素」を
用意するところから始めます。
<div id="loading" class="loading" style="display: none;">読み込み中...</div>
JavaScript で制御します。
const loadingDiv = document.getElementById("loading");
function startLoading() {
loadingDiv.style.display = "block";
searchButton.disabled = true;
}
function endLoading() {
loadingDiv.style.display = "none";
searchButton.disabled = false;
}
JavaScriptこれで、
「ステータスの文字」とは別に
「ローディング専用の表示」を持てます。
深掘りポイント
ローディング表示は、
ユーザーに「今止まっているのではなく、処理中だ」と伝える
多重クリックを防ぐ
画面の状態をわかりやすくする
という役割を持っています。
非同期処理を書くときは、
「処理の前後にローディングを挟む」
という癖をつけておくと、
どんなアプリでも安定した体験になります。
4日目の全体像をまとめる
ここまでで、
4日目にやったことを整理するとこうなります。
fetch と async/await の「骨格」はそのまま
レスポンスの中から icon や temp_f を追加で使う
単位(℃ / ℉)を状態として持ち、表示だけ切り替える
API の結果(lastData)を保存して、再描画に使う
エラー・成功・ローディングを CSS クラスで表現する
ローディング専用の要素を用意して、処理の前後で表示を切り替える
どれも「新しい難しい文法」ではなく、
「すでに知っているものの組み合わせ方」です。
今日いちばん深く理解してほしいこと
4日目の本質は、
API 通信のロジックはもう十分にできている
これからは「どう見せるか」「どう感じさせるか」を設計していく
という感覚です。
fetch
async/await
エラーハンドリング
ローディング表示
これらはすでにあなたの武器になっています。
そこに、
アイコン表示
単位切り替え
状態に応じた UI
結果の再利用(lastData)
といった“設計の工夫”を足していくことで、
「ただ動くアプリ」から「使いたくなるアプリ」に変わっていきます。
次の 5 日目では、
この天気アプリに「検索履歴」や「お気に入り都市」などを加えて、
さらに“アプリらしさ”を強めていきましょう。

