JavaScript | 1 日 90 分 × 7 日アプリ学習:ミニ総合アプリ(初級編)

JavaScript
スポンサーリンク

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

6日目のテーマは
「ミニ総合アプリを“保存できて、集計もできる、小さくても本格的なアプリ”にする」
ことです。

ここまでであなたは、

入力(タイトル+カテゴリ+完了フラグ)
一覧表示
削除
条件分岐(表示モード:すべて/未完了/完了)

を組み合わせて、かなり実用的な ToDo 風アプリを作ってきました。

6日目はここに、

入力したデータをブラウザに保存する(localStorage)
アプリ起動時に保存データを読み込む
件数の集計(合計・未完了・完了)を表示する
条件分岐で「集計表示」を切り替える

という、“アプリとしての完成度”を一段上げる要素を足していきます。


データを「ブラウザに保存する」イメージをつかむ

なぜ保存が必要なのか

今のままだと、ページをリロードすると
配列 items の中身は消えてしまいます。

せっかく入力したデータが消えるのは、
アプリとしてはかなりつらいですよね。

そこで使うのが
ブラウザに用意されている「localStorage」という仕組みです。

これは簡単に言うと、

文字列を「キーと値」で保存しておける小さな倉庫

だと思ってください。

重要なポイント:保存できるのは「文字列だけ」

localStorage はオブジェクトや配列をそのまま保存できません。
ですが、JSON という形式の文字列に変換すれば保存できます。

オブジェクトや配列
→ JSON.stringify で文字列にする
→ localStorage に保存
→ 取り出すときに JSON.parse で元に戻す

この流れを覚えれば、
「アプリの状態を保存する」という世界に一気に近づきます。


items を localStorage に保存する仕組みを作る

保存用のキーを決める

まずは「どの名前で保存するか」を決めます。

const STORAGE_KEY = "miniAppItems";
JavaScript

このキーは、
「このアプリ専用の引き出しのラベル」
のようなものです。

保存する関数を作る

function saveItems() {
  const json = JSON.stringify(items);
  localStorage.setItem(STORAGE_KEY, json);
}
JavaScript

ここでやっていることは、

items(配列)
→ JSON.stringify で文字列に変換
→ localStorage.setItem で保存

という流れです。

読み込む関数を作る

function loadItems() {
  const json = localStorage.getItem(STORAGE_KEY);
  if (!json) return;

  try {
    const data = JSON.parse(json);
    if (Array.isArray(data)) {
      items.length = 0;
      data.forEach((item) => items.push(item));
    }
  } catch (e) {
    console.error("保存データの読み込みに失敗しました", e);
  }
}
JavaScript

ここでの深掘りポイントは、

保存データがない場合もあるので null チェックをする
JSON.parse は失敗する可能性があるので try / catch で囲む
配列を丸ごと入れ替えるのではなく、中身だけ入れ替える

という「ちょっと大人な安全設計」です。


いつ保存して、いつ読み込むかを決める

読み込みのタイミング

ページを開いたとき(スクリプトが読み込まれたとき)に
一度だけ loadItems を呼びます。

loadItems();
renderList();
updateStatusMessage();
JavaScript

これで、
「前回までの items の状態」が復元されます。

保存のタイミング

items が変わるタイミングで saveItems を呼びます。

例えば、次のような場所です。

新規追加後
更新後
完了フラグ切り替え後
削除後

イメージとしては、

「配列 items をいじったら、最後に saveItems()」

という癖をつける感じです。

例:

function addItem(title, category) {
  const newItem = {
    id: nextId,
    title,
    category,
    done: false
  };
  items.push(newItem);
  nextId += 1;
  saveItems();
}
JavaScript
function toggleDone(id) {
  const target = items.find((item) => item.id === id);
  if (!target) return;
  target.done = !target.done;
  saveItems();
}
JavaScript
function deleteItem(id) {
  const newItems = items.filter((item) => item.id !== id);
  items.length = 0;
  newItems.forEach((i) => items.push(i));
  saveItems();
}
JavaScript

このように、
「状態を変えたら保存する」というルールを徹底すると、
アプリの一貫性が保ちやすくなります。


集計機能を作って「アプリの全体像」を見える化する

どんな集計を出したいか

例えば、次のような情報があると便利です。

全件数
未完了の件数
完了の件数

これを画面の上か下に表示しておくと、
「今どれくらいタスクがあるのか」が一目でわかります。

集計関数を作る

function getStats() {
  const total = items.length;
  const doneCount = items.filter((item) => item.done).length;
  const todoCount = total - doneCount;

  return {
    total,
    doneCount,
    todoCount
  };
}
JavaScript

ここでのポイントは、

filter を使って「done が true のものだけ」を数える
未完了は「全体 − 完了」で求める

というシンプルなロジックです。

集計結果を表示する

HTML に表示場所を用意します。

<div id="statsArea"></div>

JavaScript で更新関数を作ります。

const statsArea = document.getElementById("statsArea");

function renderStats() {
  const stats = getStats();

  statsArea.textContent =
    `合計: ${stats.total} 件 / ` +
    `未完了: ${stats.todoCount} 件 / ` +
    `完了: ${stats.doneCount} 件`;
}
JavaScript

そして、
renderList と同じタイミングで呼び出します。

renderList();
renderStats();
updateStatusMessage();
JavaScript

または、
items を変更する関数の最後で呼んでも構いません。


条件分岐で「集計表示のメッセージ」を変える

状態に応じてメッセージを変える

例えば、次のようなルールを作れます。

タスクが 0 件 → 「まだ何も登録されていません」
未完了が 0 件 → 「すべて完了しました。お疲れさまです!」
それ以外 → 「未完了がまだあります」

これを statusArea に表示してみます。

function updateStatusMessage() {
  const stats = getStats();

  if (stats.total === 0) {
    statusArea.textContent = "まだデータがありません。最初の1件を追加してみましょう。";
    return;
  }

  if (stats.todoCount === 0) {
    statusArea.textContent = "すべて完了しています。お疲れさまです!";
    return;
  }

  statusArea.textContent = `未完了の項目が ${stats.todoCount} 件あります。`;
}
JavaScript

ここでの深掘りポイントは、

「集計結果(数字)を条件分岐に使う」

というところです。

今までは
done フラグや viewMode を条件にしていましたが、
今日は「件数」という数値を条件に使っています。


6日目の全体イメージ(重要部分だけまとめ)

状態の一覧

items(配列:タイトル・カテゴリ・done を持つオブジェクトの集まり)
nextId(次に使う ID)
viewMode(表示モード:all / todo / done)
localStorage に保存されている JSON 文字列

これらを組み合わせて、

入力
一覧
削除
条件分岐(表示モード・完了状態・件数)

が動いています。

追加・削除・完了切り替えの流れ(要約)

入力 → バリデーション → items に push / 更新
→ saveItems() で保存
→ renderList() で一覧更新
→ renderStats() で集計更新
→ updateStatusMessage() で状態メッセージ更新

この一連の流れを意識できると、
「アプリ全体がどう動いているか」を
頭の中で追いやすくなります。


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

6日目であなたが手に入れたのは、

配列やオブジェクトを「一時的なもの」ではなく
「保存して、次回も使えるアプリの状態」として扱う感覚

と、

数を数えて、条件分岐に使い、
メッセージや UI を変えるという
「集計 × 条件分岐」の考え方です。

入力
一覧
削除
条件分岐

というキーワードは、
もう単なる文法の話ではなく、
「アプリの設計そのもの」として
あなたの中に根付き始めています。

7日目は、
このミニ総合アプリ全体を振り返りながら、
「自分は何ができるようになったのか」を
言葉にしていく仕上げの日にしましょう。

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