2日目のゴールと今日やること
2日目のテーマは
「検索・ソート・フィルタ機能を“実際に使える UI とロジック”として組み立てる」
ことです。
1日目では map / filter / sort の基本と、
リアルタイム検索・ソート・複合条件フィルタの“ロジック部分”を学びました。
2日目では、それらを UI(入力欄・ボタン)と結びつけて、実際に動く一覧アプリにする ところまで進めます。
今日のポイントは次の 3 つ。
- 状態管理(state)を導入して、検索・ソート・フィルタを一元管理
- UI 操作(検索欄・ソートボタン・年齢スライダー)とロジックをつなぐ
- map / filter / sort を組み合わせて「処理の流れ」を作る
初心者がつまずきやすい「UI とロジックの分離」を丁寧に解説します。
アプリのデータと UI を整理する
今日扱うデータ(例)
const users = [
{ id: 1, name: "Alice", age: 24 },
{ id: 2, name: "Bob", age: 30 },
{ id: 3, name: "Charlie", age: 28 },
{ id: 4, name: "David", age: 35 },
{ id: 5, name: "Eve", age: 22 }
];
JavaScriptUI のイメージ
<input id="searchInput" placeholder="名前で検索" />
<button id="sortAsc">年齢 昇順</button>
<button id="sortDesc">年齢 降順</button>
<input id="minAge" type="number" placeholder="最小年齢" />
<input id="maxAge" type="number" placeholder="最大年齢" />
<div id="list"></div>
状態管理(state)を導入する
なぜ state が必要なのか
検索 → ソート → フィルタ
のように複数の処理が重なると、
- 「今どんな検索キーワード?」
- 「今ソートは昇順?降順?」
- 「年齢フィルタは何歳〜何歳?」
といった情報を一箇所で管理したくなります。
そこで state を導入します。
state の基本形
const state = {
keyword: "",
sort: "none", // "asc" or "desc"
minAge: null,
maxAge: null
};
JavaScript状態を更新する関数
function updateState(updates) {
Object.assign(state, updates);
applyFilters();
}
JavaScriptupdateState を呼ぶだけで、
検索・ソート・フィルタが全部反映されるようにします。
applyFilters で「処理の流れ」を作る
1日目の学びを組み合わせる
function applyFilters() {
let result = [...users]; // 非破壊コピー
if (state.keyword) {
const lower = state.keyword.toLowerCase();
result = result.filter(user =>
user.name.toLowerCase().includes(lower)
);
}
if (state.minAge !== null) {
result = result.filter(user => user.age >= state.minAge);
}
if (state.maxAge !== null) {
result = result.filter(user => user.age <= state.maxAge);
}
if (state.sort === "asc") {
result = [...result].sort((a, b) => a.age - b.age);
}
if (state.sort === "desc") {
result = [...result].sort((a, b) => b.age - a.age);
}
renderList(result);
}
JavaScript深掘りポイント
ここが今日の最重要ポイントです。
- filter → filter → sort の順で処理
- すべて非破壊(元の users は壊さない)
- state の内容に応じて処理が変わる
- 最後に renderList で表示
これが「検索・ソート・フィルタの統合ロジック」です。
リアルタイム検索を state とつなぐ
searchInput.addEventListener("input", () => {
updateState({ keyword: searchInput.value });
});
JavaScript深掘りポイント
input イベントは「文字が入力されるたびに発火」します。
updateState → applyFilters → renderList
という流れが自動で走ります。
昇順 / 降順ソートボタンを作る
sortAsc.addEventListener("click", () => {
updateState({ sort: "asc" });
});
sortDesc.addEventListener("click", () => {
updateState({ sort: "desc" });
});
JavaScript深掘りポイント
sort は state.sort に文字列で保存します。
- “asc” → 昇順
- “desc” → 降順
applyFilters の中で sort の値を見て処理を切り替えます。
年齢フィルタ(複合条件)を UI とつなぐ
入力欄のイベント
minAge.addEventListener("input", () => {
const value = Number(minAge.value);
updateState({ minAge: Number.isFinite(value) ? value : null });
});
maxAge.addEventListener("input", () => {
const value = Number(maxAge.value);
updateState({ maxAge: Number.isFinite(value) ? value : null });
});
JavaScript深掘りポイント
- 数値でない場合は null に戻す
- null のときはフィルタを適用しない
- filter の条件を組み合わせるだけで複合条件になる
filter は「条件を増やすほど絞り込まれる」ので、
複合条件フィルタと相性が抜群です。
一覧表示の render 関数
function renderList(arr) {
if (!arr.length) {
listDiv.textContent = "該当するユーザーはいません。";
return;
}
let html = "";
arr.forEach(user => {
html += `<p>${user.name}(${user.age}歳)</p>`;
});
listDiv.innerHTML = html;
}
JavaScript深掘りポイント
render は「表示にだけ責任を持つ」ようにします。
ロジックと UI を分けることで、コードが読みやすくなります。
2日目のまとめ
今日あなたがやったことを整理すると、こうなります。
- state を導入して検索・ソート・フィルタを一元管理
- updateState → applyFilters → renderList の流れを作った
- filter を組み合わせて複合条件フィルタを実装
- sort を非破壊で実装(スプレッド構文)
- リアルタイム検索を input イベントで実装
- ソートボタン・年齢フィルタを UI とつなげた
どれも中級者に必須のスキルです。
今日いちばん深く理解してほしいこと
2日目の本質は、
「検索・ソート・フィルタは、state を中心に map / filter / sort を組み合わせることで“ひとつの流れ”になる」
ということです。
検索
→ 年齢フィルタ
→ ソート
→ 表示
この流れを applyFilters にまとめることで、
アプリ全体がスッキリ整理されます。
3日目では、この一覧アプリに
- タグフィルタ
- 複数条件の OR / AND
- ページネーション
- UI の改善
などを加えて、さらに“実務レベルの一覧アプリ”に育てていきます。


