【個人開発】ワールドレコード RTA を目指すツールつくりました【React/TypeScript/Jotai】

# はじめに

ワールドレコード RTA を目指すためのツールを個人開発しました！このツールでは最小ステップの入力でワールドレコードの RTA の内容を登録することが出来ていつでも見返すことができます。

# 開発理由

Youtube にはたくさんの RTA のプレイ動画があり、ワールドレコードを目指すにはこれらのプレイ動画を観ながら何度も練習することが多いと思います。プレイ動画の観ながらの練習ですと、

1. 再生・停止を繰り返しながらプレイ内容を理解
1. 自分でプレイして繰り返し

をすることが多いと思います。この方法だとプレイ内容を覚える必要があり、自分がプレイしている最中にどれだけズレているのか理解することが難しくなります。

ここでツールでは

1. 経過時間とプレイ内容をテキストで登録
1. タイマーを開始して経過時間とともにプレイ内容を表示

することでプレイ動画とのズレを認識しながら改善することが出来ます。


# 機能

![momomo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137044/b29ee7b3-f745-7635-4707-5ce51388d96f.gif)

## タイマーの開始・終了・リセット

タイマーを開始して途中で停止・リセットすることができます。

![スクリーンショット 2025-02-08 22.01.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137044/13ffc565-7b0b-62db-161a-ef757d23ba42.png)

## タイムラインの登録

何秒後に何をすべきなのか登録することができます。

![スクリーンショット 2025-02-08 22.05.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137044/3a326136-6233-fea9-abd2-8b315f686555.png)

## 現時刻の対応する内容を表示

タイマーを進めると登録したタイムラインに登録した内容を表示することができます。

![スクリーンショット 2025-02-08 21.53.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137044/dad6ab71-753d-5688-afca-3545c859fe0c.png)

# 使用技術

```
- 環境
vite: 6.0.5

- 言語
typescript: 5.6.2

- ライブラリ
react: 19.0.0
jotai: 2.11.0

- CSS
tailwindcss: 3.4.17
```

# 個人開発の気づき

「個人開発、誰にも見られてないからまあいっか」

そう思って作業をサボってしまい、完成像だけがどんどん理想的になっていく。
そして、時間だけが過ぎていき、自己嫌悪に陥る。

個人開発では、どうしてもこのような状況に陥りがちです。

私自身も、同じような経験をしてきました。
そこで、試行錯誤していく中で、モチベーションを維持するための３つの工夫を実践したところ、以前より楽しく開発ができるようになりました。

## タスクを小さくして「今日やること」を決める

まず、タスクを細分化し、今日必ず終わらせるタスクを決めました。

例えば、

- タイマーを作る
- タイムラインに登録できる


といったタスクがあったとします。

これを、

- タイマーのスタートボタンを作る
- タイマーの停止ボタンを作る
- タイムラインのデザインを決める

のように、さらに細かくします。

そして、今日やるタスクを１つ〜３つ程度決めます。

タスクを小さくすることで、達成感が生まれやすくなり、「今日もちゃんと開発できた」と実感することができます。
この積み重ねが、明日へのモチベーションに繋がります。

## 「知ってる知識９割、背伸び１割」で開発する

個人開発では、どうしても「色々な技術を試したい」という気持ちが先行しがちです。

もちろん、新しい技術に挑戦することは大切です。
しかし、知らないことばかりに挑戦してしまうと、調べるだけで膨大な時間がかかり、疲れてしまいます。
その結果、作業が滞り、挫折に繋がってしまうこともあります。

このサービスで知っている知識は

- vite を使ったプロジェクト作成
- useState を使った状態管理
- Tailwind を使ったレイアウト

です。


背伸びしたものは

- jotai を使った状態管理

です。


jotai が使えなくてもツールの開発を進めることが出来るため、達成感を得やすいです。その達成感があるうちに難しそうな jotai をチャレンジすることで知識を広げることが出来ました。

## 「作らない機能」を決める

個人開発では、どうしても理想が膨らみがちです。
「あれも作りたい、これも作りたい」
と、機能を追加していくと、完成までの道のりがどんどん長くなってしまいます。

その結果、モチベーションが低下し、挫折に繋がってしまうことがあります。

そこで、思い切って「作らない機能」を決めましょう。

このサービスで決めた作らない機能は

- ログイン機能
- シェア機能
- データベースを使った永続化

です。

# 工夫したところ

タイムラインの内容と現在時刻をコンポーネント間で共有する必要がありました。 props を使ってバケツリレーをすると実装が複雑になるので、jotai を使うことにしました。jotai は useState と同じ使い方を想定していた？くらい useState に慣れ親しんでいれば簡単に jotai を使うことができました。

# 難しかったところ

難しかったところはタイマーの終了処理です。タイムラインに登録した内容がすべて表示できたらタイマーを終了します。タイマーは `setInterval` を使って実装しておりコールバックの内容はコンポーネントをレンダリング時の値を持つため、現在時刻がいつなのか取得できませんでした。

```tsx
const startTimer = () => {
  intervalRef.current = setInterval(() => {
    // ここで jotai で管理する経過時間を更新する
    setSeconds((seconds) => seconds + 1)
    // ここで seconds を取得してもレンダリング時の値なので最新の値ではない
  }, 1000);
}

<a className='btn btn-primary' onClick={ startTimer }>Start</a>
```

jotai の setter の中だと最新の値を取得できるので、その中で登録したタイムラインをすべて表示したかの判定をするようにしました。

```ts
export const secondsAtom = atom(0)
export const elapsedTimeAtom = atom(
  null,
  (get, set) => {
    const seconds = get(secondsAtom) // ここで最新の値を取ることができる
    const timeLine = get(timeLineAtom)

    if (timeLine.length === 0) return true;

    const lastEntry = timeLine[timeLine.length - 1]
    // 経過時間と最後のタイムラインの内容と比べてまだ終わってないなら次に進む
    if (seconds < lastEntry.seconds) set(secondsAtom, seconds + 1)    
  }
)
```

# Next Action

RTA のノウハウは広く共有されるべきだと考えているのでログイン機能は作りません。誰でも登録できて URL を知っていれば誰でも利用することが目標です。そのため、Next Action をつぎのように考えています。

1. Supabase を使ったタイムラインの永続化
    1. 編集するたびにユニークな URL を生成する
1. Share ボタンを使った RTA タイムラインのシェア

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてください！
▼▼▼

https://projisou.jp