【JavaScript】外部APIからデータを取得して表示する

javascript-icon JavaScript

こんにちは、かつコーチです。

前回は「fetch APIの基本:外部データを取得する方法」で、fetchとasync/awaitを使ってデータを取得する基本の流れを解説しました。

今回はその一歩先として、実際の外部APIから複数のデータを取得し、一覧として画面に表示するところまで作っていきます。

一件だけのデータ表示とは違う難しさがあるので、順を追って見ていきましょう。

一覧データを扱うときの考え方

単一データと複数データの違い

前回扱ったのは「ユーザー1人分のデータ」でした。

今回のような一覧表示では、APIから配列(複数件のデータの集まり)が返ってくることがほとんどです。

[
  { id: 1, name: "田中太郎" },
  { id: 2, name: "佐藤花子" },
  { id: 3, name: "鈴木一郎" }
]

この配列を1件ずつ取り出して、HTMLとして組み立てていく、というのが今回のゴールです。

表示までの全体の流れ

大まかな流れは次の4ステップです。

  1. fetch でAPIにリクエストを送る
  2. .json() でJavaScriptの配列に変換する
  3. 配列を forEachmap でループし、1件ずつHTMLの文字列に組み立てる
  4. 組み立てたHTMLを、表示したい要素に流し込む

一つひとつは前回までに扱った知識の組み合わせなので、身構えなくて大丈夫です。

実際にAPIから一覧を取得して表示する

下準備:表示先のHTML

まずは、一覧を表示するための入れ物をHTMLに用意します。

<ul id="user-list"></ul>

データを取得してリスト表示する

続いて、JavaScript側の処理です。

async function showUserList() {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await response.json();

  const listElement = document.getElementById("user-list");

  users.forEach((user) => {
    const li = document.createElement("li");
    li.textContent = `${user.name}(${user.email})`;
    listElement.appendChild(li);
  });
}

showUserList();

forEach の中で document.createElement("li") を使い、1件ごとに <li> 要素を新しく作っています。

作った要素に textContent で表示内容をセットし、appendChild でリストの中に追加していく、という流れです。

このやり方は、DOM操作の基本(以前の記事「DOMとは」で扱った内容)とfetchの組み合わせそのものなので、それぞれの記事を思い出しながら読むと理解しやすいはずです。

表示するデータを整形する

APIから返ってくるデータは、そのまま表示すると読みにくいことがよくあります。

async function showUserList() {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await response.json();

  const listElement = document.getElementById("user-list");

  users.forEach((user) => {
    const li = document.createElement("li");
    // 会社名も一緒に表示するように整形する
    li.textContent = `${user.name} - ${user.company.name}`;
    listElement.appendChild(li);
  });
}

showUserList();

user.company.name のように、データの中にさらにオブジェクトがネストしている(入れ子になっている)ことも多いです。

APIのレスポンス構造は事前に console.log で確認してから、必要な項目を選んで組み立てる癖をつけておくとミスが減ります。

つまずきやすいポイント

ループの中でfetchを何度も呼んでしまう

私が実務でありがちなミスとしてやってしまったのが、「1件ずつ追加でfetchを呼ぶ」パターンです。

❌ Before:ループのたびに個別のAPIを叩いてしまう

async function showUserDetails() {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await response.json();

  const listElement = document.getElementById("user-list");

  for (const user of users) {
    // ユーザーごとに毎回、詳細情報を個別取得している
    const detailResponse = await fetch(
      `https://jsonplaceholder.typicode.com/users/${user.id}`
    );
    const detail = await detailResponse.json();

    const li = document.createElement("li");
    li.textContent = detail.name;
    listElement.appendChild(li);
  }
}

このコードは、ユーザー数が10人なら11回(一覧取得1回+詳細取得10回)もAPIを呼び出してしまいます。

私はこれを本番相当のデータ量で試したとき、表示が終わるまでに数秒かかってしまい、「なぜこんなに遅いんだろう」と原因を探すことになりました。

原因は単純で、必要ない通信を繰り返し発生させていたからです。

✅ After:最初の一覧データに必要な情報が含まれているか確認する

async function showUserDetails() {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await response.json();

  const listElement = document.getElementById("user-list");

  users.forEach((user) => {
    // 一覧取得のレスポンスにすでに必要な情報が含まれている
    const li = document.createElement("li");
    li.textContent = `${user.name}(${user.email})`;
    listElement.appendChild(li);
  });
}

一覧取得のAPIレスポンスに必要な項目がすでに含まれているなら、わざわざ1件ずつ個別のAPIを叩く必要はありません。

「本当にこの通信は必要か?」を一度立ち止まって確認するだけで、無駄な通信回数を大きく減らせます。

表示済みの要素を消さずに追加してしまう

もう一つよくあるのが、再取得のたびにリストがどんどん増えていってしまう現象です。

❌ Before:既存のリストをクリアせずに追加する

async function showUserList() {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await response.json();

  const listElement = document.getElementById("user-list");

  users.forEach((user) => {
    const li = document.createElement("li");
    li.textContent = user.name;
    listElement.appendChild(li); // ボタンを押すたびに追加され続ける
  });
}

このコードを「更新ボタン」などから複数回呼び出すと、同じユーザーが何度もリストに重複して表示されてしまいます。

✅ After:追加する前に中身を空にする

async function showUserList() {
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await response.json();

  const listElement = document.getElementById("user-list");
  listElement.innerHTML = ""; // 追加する前に一度空にする

  users.forEach((user) => {
    const li = document.createElement("li");
    li.textContent = user.name;
    listElement.appendChild(li);
  });
}

innerHTML = "" で一度中身を空にしてから追加することで、何度呼び出しても常に最新の一覧だけが表示されるようになります。

APIの取得件数を絞り込む

クエリパラメータで件数を制限する

APIによっては、URLの末尾に条件を付けることで、取得するデータの件数や内容を絞り込めます。

async function showLimitedUserList() {
  // ?_limit=3 のように条件をURLに付け加える
  const response = await fetch(
    "https://jsonplaceholder.typicode.com/users?_limit=3"
  );
  const users = await response.json();

  const listElement = document.getElementById("user-list");
  listElement.innerHTML = "";

  users.forEach((user) => {
    const li = document.createElement("li");
    li.textContent = user.name;
    listElement.appendChild(li);
  });
}

?_limit=3 の部分をクエリパラメータと呼びます。

すべてのデータを表示すると量が多くなりすぎる場合、こうしたパラメータで最初から必要な分だけ取得しておくと、後段の処理も画面表示もシンプルに保てます。

まとめ

この記事のポイント

  • 外部APIから配列で返ってくるデータは、ループで1件ずつHTML要素に変換して表示する
  • ループの中で不要なfetchを繰り返さないよう、通信回数を意識する
  • 再取得のたびに要素が重複しないよう、innerHTML = "" などで一度クリアする
  • クエリパラメータを使うと、必要な件数だけを絞り込んで取得できる

次に読むべき記事

一覧表示ができるようになったら、次はAPIとやり取りするデータの中身である「JSON」そのものの扱い方を詳しく見ていきます。

→ 次の記事:JSONの扱い方

タイトルとURLをコピーしました