JavaScript | 1 日 120 分 × 7 日アプリ学習:ToDoアプリ(設計力強化編)

JavaScript
スポンサーリンク

5日目のゴールと今日のテーマ

5日目は「ここまで作ってきた ToDo アプリの設計を、一度“俯瞰して整える日”」です。
機能はすでにかなり揃っていますが、今日は

  • 状態管理(state)の整理
  • データ構造(配列+オブジェクト)の見直し
  • 再描画ロジックの責務の明確化
  • 「壊れにくい設計」になっているかのチェック

を意識して、コードを“設計目線”で見直していきます。
新機能をガンガン足すというより、「土台を固める」日です。


現在の設計を言葉で整理してみる

今の state の構造を再確認する

ここまでで、state はだいたいこんな形になっているはずです。

const state = {
  tasks: [
    // { id, title, done }
  ],
  filter: "all",          // "all" | "active" | "completed"
  editingTaskId: null,    // 編集中のタスク id(なければ null)
};
JavaScript

ここで意識してほしいのは、「役割ごとに分けて見られるか」です。

データそのものは tasks。
表示の状態は filter と editingTaskId。

この区別ができていると、
「これはビジネスロジック」「これは UI ロジック」という線引きがしやすくなります。

タスクのデータ構造をもう一度眺める

タスクはこうでした。

{
  id: 1,
  title: "牛乳を買う",
  done: false,
}
JavaScript

ここで考えてみてほしいのは、「今後何を足せそうか」です。

例えば、期限(dueDate)、優先度(priority)、メモ(note)など。
そう考えると、「オブジェクトで持つ」という選択が
どれだけ拡張に強いかが見えてきます。


「状態を変える関数」と「画面を描く関数」をはっきり分ける

状態を変える関数たちを一覧にしてみる

今のコードには、こんな関数があるはずです。

function addTask(title) { ... }
function toggleTaskDone(id) { ... }
function deleteTask(id) { ... }
function startEditTask(id) { ... }
function finishEditTask() { ... }
function updateTaskTitle(id, newTitle) { ... }
JavaScript

これらはすべて「state を変える」役割を持っています。
共通しているのは、「最後に render を呼ぶ」こと。

ここで一度、「どこで render を呼ぶか」を整理してみます。

例えば、

  • state を変える関数の中で必ず render を呼ぶ
  • state を変える関数は render を呼ばず、呼ぶのはイベント側に統一する

どちらもアリです。
5日目では、前者(state を変える関数の中で render)を採用しつつ、
「一貫しているか」を確認してみましょう。

render の責務をもう一度確認する

render はこうなっているはずです。

function render() {
  renderTaskList();
  updateFilterButtons();
  updateTaskCount();
}
JavaScript

ここで大事なのは、

「render は state を一切変えない」

というルールです。
render は「読むだけ」、書き換えるのは state を扱う関数だけ。
この線引きができていると、バグの原因がかなり絞りやすくなります。


getVisibleTasks を“設計目線”で見直す

フィルタロジックを関数として独立させる意味

今の getVisibleTasks はこうでした。

function getVisibleTasks() {
  if (state.filter === "all") {
    return state.tasks;
  }
  if (state.filter === "active") {
    return state.tasks.filter((task) => !task.done);
  }
  if (state.filter === "completed") {
    return state.tasks.filter((task) => task.done);
  }
  return state.tasks;
}
JavaScript

ここで意識してほしいのは、

「表示に関するロジックが、state.tasks の外側にある」

ということです。

tasks 自体は「全タスク」。
getVisibleTasks は「今の filter に応じた見せ方」。

この分離ができていると、
「データをどう持つか」と「どう見せるか」が混ざりません。

フィルタ条件をオブジェクトにしてみる

設計力強化編なので、もう一歩だけ踏み込みます。

const filters = {
  all: (task) => true,
  active: (task) => !task.done,
  completed: (task) => task.done,
};

function getVisibleTasks() {
  const predicate = filters[state.filter] || filters.all;
  return state.tasks.filter(predicate);
}
JavaScript

こうすると、

  • フィルタ条件が「名前付きの関数」として整理される
  • フィルタを増やしたいときは filters に追加するだけで済む

という設計になります。

「条件を if 文でベタ書きする」のではなく、
「条件をデータ(オブジェクト)として持つ」という発想は、
中級から上級に上がるときの大きな一歩です。


タスク操作ロジックを“配列操作”の観点から整理する

追加・更新・削除を「配列操作」として眺める

タスク追加は push。
完了切り替えは find してプロパティ変更。
削除は filter で「残すものだけ残す」。

これをあえて言葉にすると、

追加は「末尾に 1 件足す」。
更新は「ある条件に一致する要素を 1 件探して、中身を書き換える」。
削除は「ある条件に一致しない要素だけを残す新しい配列を作る」。

この「配列操作のパターン」を意識しておくと、
他のアプリでも同じ考え方を使い回せます。

更新を“イミュータブル風”に書いてみる

設計力強化として、更新を少しだけ書き換えてみます。

function toggleTaskDone(id) {
  state.tasks = state.tasks.map((task) => {
    if (task.id !== id) return task;
    return {
      ...task,
      done: !task.done,
    };
  });
  render();
}
JavaScript

こうすると、

  • 元の配列を直接いじらず、新しい配列を作っている
  • 更新されたタスクも「新しいオブジェクト」として扱われる

という、いわゆる「イミュータブル寄り」の書き方になります。

必須ではありませんが、
React などのフレームワークに進むときに、
この感覚がかなり効いてきます。


「壊れにくい設計」になっているかをチェックする

機能追加を想像してみる

例えば、次の機能を足したくなったとします。

優先度(高・中・低)をタスクに持たせて、
「高優先度だけ表示」というフィルタを追加する。

このときに、

タスクのデータ構造に priority を足す。
フィルタ条件 filters に highPriority を足す。
フィルタボタンを 1 つ追加する。

これだけで済みそうか?
既存の関数を大きく書き換えなくてもいけそうか?

もし「いけそう」と感じるなら、
今の設計はかなり“拡張に強い”状態になっています。

逆に「怪しいところ」を探してみる

例えば、

  • render の中で state を書き換えていないか
  • 1 つの関数があまりに多くのことをしていないか
  • 命名があいまいで、「何をしている関数か」一瞬でわからないところはないか

こういう視点で、自分のコードを疑ってみるのも
設計力を上げるうえで大事な時間です。


5日目のまとめと、明日へのつなぎ

5日目は、機能追加よりも「設計を眺め直す」ことに時間を使いました。

あなたが今日やったのは、

state を「データ」と「表示状態」に分けて意識し直すこと。
render を「読むだけの関数」として位置づけ直すこと。
getVisibleTasks をフィルタ条件オブジェクトで整理すること。
配列操作(追加・更新・削除)をパターンとして捉え直すこと。
「この設計で機能を増やしても壊れないか?」を自分でチェックすること。

これらは全部、「中級から上に行く人」が必ず通る視点です。

明日(6日目)は、ここからさらに一歩進めて、

小さなリファクタリングを実際に手を動かしてやってみる。
命名や関数分割を変えたときに、読みやすさがどう変わるかを体感する。
「他人が読んでもわかる ToDo アプリ」に近づける。

そんな方向に進めていきます。

もし余裕があれば、今日はあえてコードを書き換えずに、
自分のコードを「設計図」として眺めてみてください。
どこが好きで、どこがモヤっとするか——そこに、あなたの次の伸びしろがあります。

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