JavaScript | 1 日 120 分 × 7 日アプリ学習:検索 & ソート機能付き一覧

APP JavaScript
スポンサーリンク

6日目のゴールと今日やること

6日目のテーマは
「検索 × ソート × フィルタ一覧アプリを“読みやすく・直しやすく・拡張しやすい設計”に進化させる」
ことです。

ここまでであなたは、

  • リアルタイム検索
  • 昇順 / 降順ソート
  • 複合条件フィルタ
  • タグフィルタ(AND / OR)
  • ページネーション
  • デバウンス
  • ハイライト表示
  • 条件保存(localStorage)
  • データ追加・削除

といった、実務レベルの一覧アプリの基礎をすでに作り上げています。

6日目は、これらを 「設計として整理する」 回です。

つまり、
map / filter / sort を“アプリ全体の型”として扱えるようにする
ことが目的です。


アプリ全体の構造を「3 層」で整理する

一覧アプリは、次の 3 層で考えると劇的に読みやすくなります。

データ処理層(最下層)

  • applyKeywordFilter
  • applyAgeFilter
  • applyTagFilter
  • applySort
  • applyPagination

ここは map / filter / sort / slice の世界 です。

状態管理層(state)

  • filters
  • sortState
  • pagination

アプリの“今”を表す情報がここに集まります。

UI 層(最上層)

  • renderList
  • updateSortButtons
  • イベント処理(検索、ソート、タグ、ページ移動など)

UI は「表示にだけ責任を持つ」ようにします。

この 3 層構造を意識すると、
どこで何をしているかが一気に見通しやすくなります。


データ処理層を「小さな関数の組み合わせ」にする

applyFilters の完成形

function applyFilters() {
  let result = [...users];

  result = applyKeywordFilter(result);
  result = applyAgeFilter(result);
  result = applyTagFilter(result);
  result = applySort(result);
  result = applyPagination(result);

  renderList(result);
  updateSortButtons();
  saveState();
}
JavaScript

深掘りポイント

ここが 6 日目の最重要ポイントです。

  • 巨大な関数ではなく、小さな関数の組み合わせ
  • map / filter / sort / slice を順番に適用
  • 非破壊操作(元の users を壊さない)
  • 最後に UI と保存処理を呼ぶだけ

これが「中級者の一覧アプリの型」です。


各フィルタ関数を“読みやすい形”にする

キーワードフィルタ

function applyKeywordFilter(arr) {
  if (!filters.keyword) return arr;

  const lower = filters.keyword.toLowerCase();
  return arr.filter(user =>
    user.name.toLowerCase().includes(lower)
  );
}
JavaScript

年齢フィルタ

function applyAgeFilter(arr) {
  let result = arr;

  if (filters.minAge !== null) {
    result = result.filter(user => user.age >= filters.minAge);
  }

  if (filters.maxAge !== null) {
    result = result.filter(user => user.age <= filters.maxAge);
  }

  return result;
}
JavaScript

タグフィルタ(AND / OR)

function applyTagFilter(arr) {
  if (filters.tags.length === 0) return arr;

  if (filters.tagMode === "OR") {
    return arr.filter(user =>
      user.tags.some(tag => filters.tags.includes(tag))
    );
  }

  return arr.filter(user =>
    filters.tags.every(tag => user.tags.includes(tag))
  );
}
JavaScript

ソート

function applySort(arr) {
  if (!sortState.key) return arr;

  const key = sortState.key;
  const order = sortState.order;

  return [...arr].sort((a, b) => {
    if (order === "asc") {
      return a[key] > b[key] ? 1 : -1;
    } else {
      return a[key] < b[key] ? 1 : -1;
    }
  });
}
JavaScript

ページネーション

function applyPagination(arr) {
  const start = (pagination.page - 1) * pagination.perPage;
  return arr.slice(start, start + pagination.perPage);
}
JavaScript

深掘りポイント

  • すべて非破壊(arr を壊さない)
  • filter は「条件を増やすほど絞り込まれる」
  • sort は「比較関数」で自由に並び替え
  • slice は「配列の一部を切り出す」

これらを組み合わせるだけで、
実務レベルの一覧処理が作れます。


状態管理層を整理する(責務の分離)

filters(検索条件)

const filters = {
  keyword: "",
  minAge: null,
  maxAge: null,
  tags: [],
  tagMode: "OR"
};
JavaScript

sortState(ソート条件)

const sortState = {
  key: null,
  order: "asc"
};
JavaScript

pagination(ページ情報)

const pagination = {
  page: 1,
  perPage: 3
};
JavaScript

深掘りポイント

state を分割することで、

  • 何がどこで使われているかが明確
  • applyFilters が読みやすくなる
  • 機能追加がしやすい

これが「中級者の設計」です。


UI 層を整理する(表示とイベントを分離)

renderList(表示にだけ責任を持つ)

function renderList(arr) {
  if (!arr.length) {
    listDiv.textContent = "該当するユーザーはいません。";
    return;
  }

  let html = "";
  arr.forEach(user => {
    const name = highlight(user.name, filters.keyword);
    html += `<p>${name}${user.age}歳)</p>`;
  });

  listDiv.innerHTML = html;
}
JavaScript

updateSortButtons(ソート状態を UI に反映)

function updateSortButtons() {
  sortAge.textContent =
    sortState.key === "age"
      ? `年齢 ${sortState.order === "asc" ? "▲" : "▼"}`
      : "年齢 ▲▼";

  sortName.textContent =
    sortState.key === "name"
      ? `名前 ${sortState.order === "asc" ? "▲" : "▼"}`
      : "名前 ▲▼";
}
JavaScript

深掘りポイント

UI は「表示にだけ責任を持つ」
ロジックは「処理にだけ責任を持つ」

この分離ができると、
アプリが一気に読みやすくなります。


6日目のまとめ

今日あなたがやったことを整理すると、こうなります。

  • 一覧アプリを「データ処理層・状態管理層・UI 層」に分割
  • applyFilters を小さな関数の組み合わせに再構築
  • map / filter / sort / slice を“型”として扱えるようになった
  • state を filters / sortState / pagination に分割
  • UI とロジックを完全に分離
  • 非破壊操作を徹底して安全なコードにした

どれも中級者に必須のスキルです。


今日いちばん深く理解してほしいこと

6日目の本質は、

「一覧アプリは、map / filter / sort を“設計として扱う”ことで、読みやすく・直しやすく・拡張しやすくなる」

ということです。

検索
→ 年齢フィルタ
→ タグフィルタ
→ ソート
→ ページネーション
→ 表示

この流れを applyFilters にまとめ、
小さな関数の組み合わせにすることで、
アプリは“中級者の設計”に進化します。

7日目では、この一覧アプリを
中級編の完成形としてまとめる
回に入ります。

あなたのアプリが「本当に使えるツール」になる瞬間です。

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