プロへの道 » フロントエンドコース » ユニット3

フロントエンドコース ユニット3 | 目安: 120時間 (約1.5ヶ月)

データと非同期 ― 閉じても消えない、外とつながる

ユニット2までのアプリには、2つの弱点がありました。「ページを閉じると全部消える」と「自分のページの中で完結している」です。このユニットで、保存 (localStorage) と通信 (fetch) を手に入れて、両方を解決します。アプリが一気に実用品になります。

このユニットのゴール データをJSONで保存・復元でき、外部のAPIから取得したデータを画面に表示できるようになる。

進め方の地図

やること 仕上がるもの
1週目 授業1: JSON ― データの共通語 JSONの読み書き練習
2週目 授業2: localStorage ― ブラウザに保存する 消えないメモ帳
3〜4週目 授業3: fetch ― 外の世界からデータを取る 郵便番号 → 住所の検索
5週目 授業4: 待つ・失敗する ― 非同期の作法 読み込み中表示とエラー対応
6週目 月末制作 保存つきToDo + 住所検索アプリ

授業1: JSON ― データの共通語

JSON (ジェイソン) は、データを文字で書き表す世界共通の形式です。見た目はユニット2の「オブジェクトの配列」とほぼ同じなので、あなたはもう8割読めます。保存も通信も、データは全部JSONで動きます。

例題 (リードつき) | オブジェクトとJSONを行き来する
  1. オブジェクトをJSON文字列にするコンソールで試します。
    const item = { name: "メロンパン", price: 180 };
    const text = JSON.stringify(item);
    console.log(text); // '{"name":"メロンパン","price":180}'
  2. JSON文字列をオブジェクトに戻す
    const back = JSON.parse(text);
    console.log(back.price); // 180
  3. 変換の理由を知る保存も通信も「文字しか運べない」のです。だから、出発時に stringify (文字にする)、到着時に parse (戻す) をします。この往復だけ覚えれば、JSONは卒業です。
  4. 本物のJSONを見るブラウザで https://zipcloud.ibsnet.co.jp/api/search?zipcode=5940041 を開いてみましょう。郵便番号データがJSONで返ってきます。これが授業3で取りに行くデータです。
演習 1-A (ヒントだけ) | 自分のデータをJSON化する

お題: ユニット2のクイズの問題データ (オブジェクトの配列) を stringifyparse で往復させて、往復後も for...of でちゃんと表示できることを確かめます。

ヒント: JSON.stringify(data, null, 2) と書くと、改行と字下げつきの読みやすい形で出力されます。中身の確認に便利な小技です。

授業2: localStorage ― ブラウザに保存する

localStorage (ローカルストレージ) は、ブラウザの中にある小さな保存箱です。ページを閉じても、パソコンを再起動しても残ります。使うのは setItem (しまう) と getItem (取り出す) の2つだけです。

例題 (リードつき) | 閉じても消えないメモ帳
  1. HTML: <textarea id="memo"></textarea> を1つ置きます。
  2. 入力のたびに保存する
    const memo = document.querySelector("#memo");
    
    memo.addEventListener("input", () => {
      localStorage.setItem("memo", memo.value);
    });
  3. 開いたときに復元するスクリプトの先頭に1行足します。
    memo.value = localStorage.getItem("memo") || "";
    || "" は「まだ保存がなければ空文字」という保険です。
  4. 奇跡を確認する何か書いて、タブを閉じて、開き直します。文章が残っていれば成功です。
  5. 保存箱の中を覗くF12 → Applicationタブ → Local Storage で、保存された中身を直接見られます。デバッグの強い味方です。
演習 2-A (リードつき) | 配列を保存する ― JSONとの合体

お題: localStorageは文字しかしまえません。ユニット2の「リスト追加」(演習5-B) に、配列ごと保存・復元する機能を足します。

  1. しまうとき: localStorage.setItem("list", JSON.stringify(listData));
  2. 取り出すとき: const listData = JSON.parse(localStorage.getItem("list") || "[]");
  3. 復元の描画: ページを開いたとき、取り出した配列を for...of で回して li を作り直します。
この3点セット (stringifyでしまう / parseで出す / 開いたら描き直す) が、保存つきアプリの万能の型です。月末制作のToDoアプリも、この型そのままで作れます。
演習 2-B (ヒントだけ) | 設定の記憶

お題: ページに「文字を大きくする」切り替えボタンをつけ、選んだ状態が次に開いたときも続いているようにします。

ヒント: 保存するのは "large" / "normal" のような短い文字で十分です。開いたときに読んで、body にクラスをつけ外しします。

授業3: fetch ― 外の世界からデータを取る

fetch (フェッチ) は「URLにデータを取りに行く」命令です。世の中には、誰でも使ってよいデータの窓口 = 公開APIがたくさんあります。今回は、郵便番号から住所を返してくれる無料API (zipcloud) を使います。通信には時間がかかるので、「待つ」ための書き方 async / await もセットで覚えます。

例題 (リードつき) | 郵便番号 → 住所を取ってくる
  1. まず観察授業1の手順4で見たJSONをもう一度開き、住所が results の中にあることを確認します。取りに行く前に、形を見る ― これがAPIの作法その1です。
  2. 取りに行く関数を書く
    async function searchAddress(zipcode) {
      const res = await fetch(
        "https://zipcloud.ibsnet.co.jp/api/search?zipcode=" + zipcode
      );
      const data = await res.json();
      return data.results;
    }
    await は「返事が来るまでここで待つ」、async は「この関数の中でawaitを使います」という宣言です。
  3. 呼んで表示する
    const results = await searchAddress("5940041");
    console.log(results[0].address1 + results[0].address2 + results[0].address3);
    コンソールに住所が出れば、あなたのコードは今、インターネットの向こうと会話しました。
  4. 画面とつなぐ入力欄 + 検索ボタンを作り、ボタンのクリックで searchAddress を呼んで、結果を p に表示します。ユニット2の「3行の型」との合体です。
赤いエラー (CORSなど) が出たら: 通信系のエラーは、コードが正しくても環境側の事情で起きることがあります。エラー文をそのままAIに貼って意味を聞く + スタッフに報告、が正しい初動です。「自分が悪いに違いない」と一人で抱えないのが、通信デバッグの鉄則です。
演習 3-A (リードつき) | 結果が複数・ゼロのときに備える

お題: 郵便番号によっては、住所が複数返ったり、見つからなかったり (resultsがnull) します。検索アプリを次の仕様に育てます。

  1. 見つからないとき: if (results === null) なら「見つかりませんでした。番号を確かめてください」と表示します。
  2. 複数のとき: for...of で全部 li にして表示します。
  3. 試す番号: 普通に出る番号 (例: 5940041)、存在しない番号 (例: 0000000) の両方でテストします。うまくいかない場合を先に試すのが、APIの作法その2です。

授業4: 待つ・失敗する ― 非同期の作法

通信は「遅い・失敗する」ものです。プロのアプリとの差は、この2つへの備えに出ます。備えは2点セットです ― 読み込み中の表示と、try / catchでの失敗の受け止め

例題 (リードつき) | 検索アプリに2点セットを足す
  1. 読み込み中を出すボタンが押されたら、まず結果欄に「検索中…」を表示してからfetchします。返事が来たら上書きします。
  2. 失敗を受け止める
    try {
      const results = await searchAddress(zip);
      // ここに成功時の表示
    } catch (e) {
      resultEl.textContent = "通信に失敗しました。少し待ってもう一度試してください。";
    }
    tryの中で失敗が起きると、catchに飛びます。利用者には「次にどうすればいいか」まで伝えるのが優しいエラー表示です。
  3. 失敗を再現するWi-Fiを切って検索ボタンを押し、catchがちゃんと働くのを確認します。エラー表示は、エラーを起こしてテストする ― 当たり前のようで、忘れる人が多い作法です。
  4. 連打対策検索中はボタンを disabled = true にして、終わったら戻します。細部ですが、こういう1行が「仕事の品質」です。

月末制作: 保存つきToDo + 住所検索アプリ

月末制作

2本立てです。1本目は保存の総まとめ、2本目は通信の総まとめです。

  1. 1本目: 消えないToDoアプリStep 3の見本 todo-mihon.html を出発点に、①localStorage保存 (授業2の万能の型) ②完了の切り替え ③削除ボタン ④「残り◯件」表示、の4機能を足します。データは { text: "牛乳を買う", done: false } のオブジェクトの配列で持ちましょう。
  2. 2本目: 住所検索アプリ授業3〜4で育てた検索アプリを仕上げます。読み込み中表示・エラー対応・見つからない対応の3点がそろっていること。見た目もFlexboxで整えて「人に使ってもらえる顔」にします。
  3. 仕上げの検査2本とも、スタッフに2分間自由に触ってもらいます。「説明なしで使えたか」「変な操作で壊れなかったか」が合格基準です。
  4. GitHubで公開コミットを積みながら作り、GitHub Pagesで公開して、ポートフォリオの種に加えます。
余力があれば合体: ToDoに「買い物の予定」を入れる人のために、住所検索をToDoのおまけ機能としてつける ― など、2本を1つのページにまとめる構成も歓迎です。設計から自分で決めてみましょう。

つまずきやすいポイント

「awaitを書く場所」で混乱したら: 合言葉は「待つ行の頭にawait、その関数の頭にasync」です。コンソールでは最初からawaitが使えるので、まずコンソールで1行ずつ動かしてから、関数にまとめると混乱しません。
localStorageが「前のデータ」を返してきて混乱したら: 開発中の古い保存が残っているだけです。F12 → Application → Local Storage で右クリック → 削除すれば、まっさらから試せます。

発展チャレンジ (余力のある方へ)

発展チャレンジ
  • 無料の天気API「Open-Meteo」を調べて、和泉市の今日の気温を表示してみましょう。鍵 (APIキー) なしで使えるので、2つ目のAPIの練習に最適です。
  • ToDoに「期限」の項目を足し、期限が近いものを上に並べ替えてみましょう (配列の sort を調べることになります)。
  • 「APIキーとは何か・なぜ秘密にするのか」を調べてメモしましょう。鍵つきAPIを安全に使う知識は、ユニット5 (サーバー越境) で本領を発揮します。

できたチェック