【Next.js】Githubのような勉強記録アプリ①:簡単なTimer実装

勉強記録アプリ_サムネイル Programming

最近は、なんでもAIがコードを書いてくれる時代ですが、あえてAIを使わずにコードを書いてみました。もちろん、最終的にはAIにコードを見てもらいました☺️(私の心強い先生です!)

AIを使えば効率よく開発できますし、時間短縮にもなります。ただ、自分はまだ知識も経験も浅いため、基礎的な部分は自分の力で書けるようになりたいと思いました。この1つのアプリを作っただけで大きく変わるとは思いませんが、こうした経験を積み重ねることで、少しずつ成長できると信じています。

この記事でわかること
  • Hookの宣言
  • Timer記録
  • 設計

勉強記録アプリについて

今回は、勉強記録アプリケーションを制作しています。GitHubのように、1年間単位で勉強した日が一目で分かるようなシンプルで分かりやすいUIを目指しています。

study-tracker-main

開発環境

今回の開発では、以下の技術を使用しています。

  • Next.js(App Router)
  • TypeScript
  • Tailwind CSS
  • localStorage

バックエンドは使用せず、まずはフロントのみで動くように構成しました。

設計

最初に、「どのような機能が必要なのか」を整理しました。その上で、コンポーネント・フック・タイプ・関数などを役割ごとに分けて設計しています。

  • Page
    → 全体のレイアウト・表示管理
  • Component
    → Timer、Grass などのUI
  • Hook
    → useTimer(時間の管理)、再利用可能
  • Type
    → StudyRecord などのデータ構造
  • Function
    → localStorageの保存・取得、フォーマット処理

Type定義

まずは、保存するデータの形を決めました。

Type定義

ID(固有番号)に加えて、日付・勉強内容・勉強時間を保存します。データの形を先に決めることで、その後の実装をスムーズに進めることができました。

このデータは画像のようにローカルストレージに保存します。

localstorage
コードを見る
export type StudyRecord = {
  id: string;
  date: string;
  startTime: number;
  endTime: number;
  duration: number;
  title: string;
  detail?: string;
};

useTimer(カスタムフック)

タイマーのロジックは、カスタムフックとして分離しました。

コード説明

勉強開始時間と終了時間を記録して、勉強時間を計算します。

State変数宣言
  • startTime
    スタート時間を管理するStateです。(number または null)
  • isRunning
    タイマーが動いているかどうかを判別します。
start()関数
  • isRunningがtrueの場合は処理しない
  • Date.now()で現在時刻を取得
  • Stateを更新してタイマーを開始
end()関数
  • isRunningがfalse、またはstartTimeがnullの場合は処理しない
  • 現在時刻からstartTimeを引いて、経過時間を計算
  • isRunningをfalseに変更
  • 計算した値をreturn
コードを見る
function useTimer() {
  const [startTime, setStartTime] = useState<number | null>(null);
  const [isRunning, setIsRunning] = useState(false);

  const start = () => {
    if (isRunning) return;

    const now = Date.now();
    setStartTime(now);
    setIsRunning(true);
  };

  const end = () => {
    if (!isRunning || startTime == null) return;

    const now = Date.now();
    const duration = now - startTime;

    setIsRunning(false);

    return {
      startTime,
      endTime: now,
      duration,
    };
  };

  return { start, end, isRunning, startTime };
}

コードのポイント

時間の管理は Date.now() を使い、ミリ秒単位でシンプルに扱うようにしました。

  • 開始 → 現在時刻を保存
  • 終了 → 差分で時間を計算

また、ロジックとUIを分離することで、再利用しやすく、見通しの良いコードになりました。

Page(UI)

UIはシンプルに、

  • 勉強内容を入力
  • Startで開始
  • Endで終了

という流れにしました。

最小限の構成にすることで、まずは動くものを作ることを意識しました。

まとめ

今回は、勉強記録アプリの第一ステップとして、タイマー機能を実装しました。シンプルですが、アプリの土台になる重要な部分だと感じました。

次回は、記録したデータをlocalStorageに保存する処理についてまとめる予定です。

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