12.4 クラスによるデータ管理とUI反映

取得したデータを整理するための 「クラス」 と、画面を書き換えるための 「DOM 操作」 を追加します。
book-search.js の末尾に以下のソースを追加します

ソースフォルダ:public/ch12

ファイル名:book-search.js

// 書籍データを効率的に管理するためのクラス
class BookManager {
    constructor() {
        this.books = []; // データを保持するプロパティ
    }

    // 取得したデータをクラス内にセットします
    setBooks(data) {
        this.books = data;
    }

    // 画面表示に不要な情報を削り、整形されたデータを返します
    getProcessedItems() {
        // mapを使って、idとtitleだけの新しいオブジェクト配列を作成します
        return this.books.map(book => ({
            id: book.id,
            title: book.title
        }));
    }
}

// 画面のリスト(ul要素)を更新する関数
function renderList(items) {
    const listElement = document.querySelector("#book-list");
    listElement.innerHTML = ""; // 一度中身を空にして初期化します

    // 1件ずつHTML要素(liタグ)を作成して追加します
    items.forEach(item => {
        const li = document.createElement("li"); // <li>を作成
        li.textContent = `[ID:${item.id}] ${item.title}`; // テキストを設定
        listElement.appendChild(li); // ulの中に追加
    });
}

解説

23 行目から始まる renderList 関数は、取得したデータを実際に画面に表示する役割を持ちます。

関数の責務と分離の意図

なぜこの関数を独立させているのでしょうか?

【設計の原則:責務の分離】
  • BookManager クラス: データの管理・加工
  • renderList 関数: 画面への表示
  • setupSearch 関数: 検索機能(後述)

それぞれが明確な役割を持つことで、「どこを修正すればいいか」が一目瞭然になります。例えば、表示デザインを変更したい場合は、renderList 関数だけを修正すればよく、データ管理のコードには手を付ける必要がありません。

DOM 操作の流れ(ステップバイステップ)

24 行目から 32 行目の処理を順番に見ていきましょう

【ステップ 1】要素の取得

HTML の <ul id=”book-list”></ul>要素を JavaScript から操作できるオブジェクトとして取得します。
第 8 章で学んだ querySelector ですね。

24: const listElement = document.querySelector("#book-list");
【ステップ 2】既存内容のクリア

リストの中身を空にします。これを行わないと、renderList を呼ぶたびに古いデータが残ったまま新しいデータが追加されてしまいます。

25: listElement.innerHTML = "";
【動作イメージ】

初回表示: [データ A, データ B, データ C]
クリアなし: [データ A, データ B, データ C, データ A, データ B, データ C]
クリアあり: [データ A, データ B, データ C] ← 毎回リセットされる

【ステップ 3-6】forEach でのループ処理

引数 items の配列要素 1 つ 1 つに対して処理を実行します。

28: items.forEach(item => {
29:     const li = document.createElement("li");
30:     li.textContent = `[ID:${item.id}] ${item.title}`;
31:     listElement.appendChild(li);
32: });

各ループで行うこと:

  1. 新しい<li>要素を作成(29行目)
  2. その<li>の中身を設定(30行目)
  3. <ul>の中に追加(31行目)

textContent と innerHTML の違い

61 行目で textContent を使っていますが、innerHTML との違いは何でょうか。

【textContent(推奨)】
  • テキストとして扱う
  • HTML タグは無効化される
  • XSS 攻撃を防げる(セキュリティ上安全)
【innerHTML】
  • HTML として解釈されるため、タグも有効になる
  • ユーザーが入力したデータを含む場合は危険
【具体例】

悪意のあるデータ: “<script>alert(‘攻撃’)</script>”

textContent の場合:

→ “<script>alert(‘攻撃’)</script>” とそのまま表示される(安全)

innerHTML の場合:

→ スクリプトが実行されてしまう(危険)

今回は単純なテキスト表示なので textContent を使っています。