はじめに
Reactを学習する際、「どのアプリから始めればいいのか」「次にどんなアプリに取り組むべきか」と悩む方は多いのではないでしょうか。
本記事では、それぞれの難易度や学習ポイントを詳しく解説します。これらは段階的に難易度が上がる設計になっており、Reactとモダンな開発手法を体系的に習得できます。
この記事で分かること
- 各アプリの難易度と学習時間の目安
- 実装されている機能と技術要素
- 具体的なコード例と実装ポイント
- 次のステップとして取り組むべき拡張機能
アプリ比較表
| アプリ名 | 難易度 | 学習時間目安 |
|---|---|---|
| Todoリストアプリ | 初級 | 5-8時間 |
| パスワードジェネレーターアプリ | 初級 | 5-8時間 |
| カウントダウンタイマーアプリ | 初級〜中級 | 6-10時間 |
| カラーピッカーアプリ | 初級〜中級 | 6-10時間 |
| 単位変換アプリ | 初級〜中級 | 6-10時間 |
| お絵描きアプリ | 初級〜中級 | 6-10時間 |
| 電卓アプリ | 中級 | 8-12時間 |
| レシピ検索アプリ | 中級 | 8-12時間 |
| マークダウンエディタアプリ | 中級 | 10-15時間 |
| RSSリーダーアプリ | 中級 | 10-15時間 |
| タイムゾーン変換アプリ | 中級〜上級 | 10-15時間 |
| 読書記録アプリ | 中級〜上級 | 12-18時間 |
| 家計簿アプリ | 中級〜上級 | 12-18時間 |
| カレンダーアプリ | 上級 | 15-20時間 |
| 画像エディタアプリ | 上級 | 15-20時間 |
Todoリストアプリ
概要
タスク管理アプリです。タスクの追加、完了、削除、フィルタリング機能を備えています。
ソースコード
機能要件
-
タスク管理
- タスクの追加(テキスト入力)
- タスクの完了/未完了切り替え(チェックボックス)
- タスクの削除
- 完了済みタスクの一括削除
-
フィルタリング
- 全てのタスク表示
- アクティブなタスクのみ表示
- 完了済みタスクのみ表示
-
データ永続化
- LocalStorageを使用してタスクを保存
- ページをリロードしてもデータを保持
実装ポイント
カスタムフック
このカスタムフックでは、ビジネスロジックを一箇所に集約することで、コンポーネントの見通しを良くしています。フィルタリングロジックをフック内で実装することで、コンポーネント側は表示に専念でき、責務の分離が実現されています。
拡張アイディア
-
優先度機能
- タスクに優先度(高/中/低)を追加
- 優先度でソート機能
-
期限管理
- タスクに期限を設定
- 期限切れのタスクをハイライト表示
-
カテゴリー分類
- タスクにカテゴリータグを追加
- カテゴリー別にフィルタリング
-
ドラッグ&ドロップ
- タスクの順序をドラッグ&ドロップで変更
- react-beautiful-dndライブラリを活用
学べること
-
Reactの基礎
- コンポーネントの分割と再利用
-
useState、useEffectの基本的な使い方 - イベントハンドリング
-
状態管理
- カスタムフックを使った状態管理
- LocalStorageを使ったデータ永続化
-
TypeScript
- インターフェース定義
- Union型の活用
- Props型定義
-
実践的なパターン
- CRUD操作の実装
- フィルタリングロジック
- 配列操作(
map,filter)
パスワードジェネレーターアプリ
概要
ランダムなパスワードを生成するアプリです。パスワード長の調整、文字種の選択、強度表示、クリップボードコピー機能を備えています。
ソースコード
機能要件
-
パスワード生成
- パスワード長設定(4-32文字、スライダー)
- 文字種選択(大文字・小文字・数字・記号のチェックボックス)
- 各文字種から最低1文字を確保
- ランダム生成とシャッフル
-
強度表示
- パスワード強度の視覚的表示(プログレスバー)
- 強度評価(弱い・普通・強い・非常に強い)
- 色分けによる直感的なフィードバック
-
コピー機能
- クリップボードへのワンクリックコピー
- Clipboard API使用(フォールバック実装付き)
- コピー成功のフィードバック
-
自動生成
- アプリ起動時に自動でパスワード生成
- 設定変更時にも生成可能
実装ポイント
パスワード生成
パスワード生成ロジックでは、選択された各文字種から最低1文字を確保することで、生成されたパスワードが確実に選択された文字種を含むようにしています。まず各文字種から1文字ずつ追加し、残りの長さをランダムに埋めた後、シャッフルすることで、パターンが予測しにくいパスワードを生成します。文字種が1つも選択されていない場合はエラーをスローし、不正な操作を防いでいます。
強度計算
パスワード強度は、長さと文字種の数に基づいて計算されます。記号の使用にはスコアを与え、他の文字種より重視することで、より安全なパスワード生成を促進しています。スコアをパーセンテージに変換し、視覚的なプログレスバーで表示することで、ユーザーに直感的なフィードバックを提供します。
クリップボードコピー機能
モダンなClipboard APIを優先的に使用し、失敗した場合は古いブラウザ向けのフォールバック実装に切り替えます。フォールバックでは、一時的なtextarea要素を作成してコピー操作を行い、操作後は要素を削除してDOMを汚染しないようにしています。両方の方法が失敗した場合でも、アプリがクラッシュせずにfalseを返すことで、エラーハンドリングが適切に行われています。このパターンは、クロスブラウザ互換性を保つ実践的な手法です。
拡張アイディア
-
パスワード履歴
- 生成したパスワードの履歴保存
- LocalStorageでの永続化
- 履歴からの再選択機能
- 履歴のクリア機能
-
複数パスワード生成
- 一度に複数のパスワードを生成
- バッチ生成機能
- 生成結果の一覧表示
-
QRコード生成
- パスワードのQRコード化
- スマートフォンへの転送機能
学べること
-
アルゴリズム実装
- ランダム文字列生成
- シャッフルアルゴリズム
- 強度計算ロジック
- スコアリングシステムの設計
-
Browser API活用
- Clipboard APIの使用
- フォールバック実装パターン
- 古いブラウザとの互換性確保
- try-catchによるエラーハンドリング
カウントダウンタイマーアプリ
概要
設定した時間をカウントダウンするシンプルなタイマーアプリです。プリセットボタン、開始・一時停止・リセット機能、アラーム音を備えています。
ソースコード
機能要件
-
タイマー設定
- 1〜60分の範囲で時間設定
- 数値入力による任意の時間設定
- 入力値の自動バリデーション(範囲外の値を自動補正)
- プリセットボタン(1分、3分、5分、10分)
-
タイマー操作
- 開始ボタン(設定時間からカウントダウン開始)
- 一時停止ボタン(カウントダウンを一時停止)
- リセットボタン(タイマーを初期状態に戻す)
- タイマー実行中はプリセット選択を無効化
-
表示機能
- MM:SS形式での残り時間表示
- ステータスメッセージ表示(待機中、実行中、一時停止中、完了)
- 2桁ゼロパディング表示
-
アラーム機能
- タイマー完了時にアラーム音を再生
- Web Audio APIによる音声生成
- 周波数・音量・再生時間のカスタマイズ可能
実装ポイント
useEffectとクリーンアップ
タイマー機能の実装では、useEffectとsetIntervalを組み合わせていますが、最も重要なのはクリーンアップ関数の実装です。コンポーネントがアンマウントされる際や、依存配列の値が変わってエフェクトが再実行される前に、clearIntervalを呼び出してタイマーをクリアしています。このクリーンアップ処理を省略すると、コンポーネントがアンマウントされた後もタイマーが動き続け、メモリリークや予期しない状態更新エラーが発生します。
Web Audio APIによるアラーム音生成
Web Audio APIを使用して、外部音声ファイルなしでアラーム音を生成しています。クロスブラウザ対応のため、webkitAudioContextもフォールバックとして用意しています。try-catchによるエラーハンドリングにより、Audio APIが利用できない環境でもアプリがクラッシュしません。
入力バリデーションと範囲制限
リアルタイムで入力値を検証し、範囲外の値を自動的に補正することで、ユーザーが無効な値を入力できないようにしています。最小値(1分)未満や最大値(60分)超過の値は即座に境界値に修正され、ユーザーに明確なフィードバックを提供します。空文字列を許可することで、ユーザーが全削除して新しい値を入力する際の操作性を損ないません。
拡張アイディア
-
複数タイマー機能
- 複数のタイマーを同時に管理
- タブUIでタイマーを切り替え
- 各タイマーに名前を付ける機能
-
カスタムアラーム音
- アラーム音の種類を選択(ビープ音、チャイム音など)
- 音声ファイルのアップロード機能
- 音量・音色の調整UI
-
タイマー履歴
- 過去に使用した時間設定を記録
- よく使う時間をお気に入り登録
- 履歴から素早く再設定
-
バックグラウンド通知
- ブラウザタブが非アクティブでも通知
- Notification APIの活用
- タイトルバーに残り時間を表示
学べること
-
タイマー実装の基礎
-
useEffectとsetIntervalの組み合わせ - クリーンアップ関数の重要性
- メモリリーク防止のパターン
-
-
Web Audio API
- AudioContextの基本的な使い方
- Oscillatorによる音声合成
- GainNodeによる音量制御
- クロスブラウザ対応
-
入力バリデーション
- リアルタイム入力検証
- 範囲制限の実装
- ユーザビリティを考慮した補正処理
カラーピッカーアプリ
概要
RGBスライダーとプリセットカラーを使った色選択アプリです。色の保存・管理、クリップボードコピー機能を備えた、視覚的でインタラクティブなUIが学べます。
ソースコード
機能要件
-
カラー選択
- RGBスライダーによる色調整(各色0-255)
- プリセットカラーからの選択(基本8色)
- リアルタイムカラープレビュー
- 16進数カラーコードの表示
-
カラー管理
- カラーコードのクリップボードコピー
- カラーの保存(最大10色)
- 保存済みカラーの削除(右クリック)
- LocalStorageでの永続化
実装ポイント
色変換
1桁の16進数に必ずゼロパディングを行うことにより、常に正しい6桁のカラーコードを生成できます。RGBとHEXの相互変換を実装することで、異なる色表現形式をシームレスに扱えます。
保存カラー管理
最大10色の制限を設け、新しい色が追加されると最も古い色が自動的に削除されるFIFOキューの実装により、メモリ使用量を抑えています。重複チェックを行うことで、同じ色が複数保存されることを防ぎ、データの整合性を保っています。
拡張アイディア
-
カラーパレット機能
- 複数色を組み合わせたパレット作成
- パレットのエクスポート/インポート
- カラースキーム(補色、類似色など)の自動生成
-
配色提案機能
- 選択色に基づいた配色の自動提案
- アクセシビリティチェック(コントラスト比)
- カラーハーモニー理論に基づく提案
-
エクスポート/インポート
- 保存カラーのJSON形式エクスポート
- 他のツールからのカラーパレットインポート
- CSS変数形式での出力
学べること
-
色空間の理解
- RGB/HEXの色表現方式
- 色空間変換のアルゴリズム
- 16進数と10進数の相互変換
単位変換アプリ
概要
長さ・重さ・温度の単位を変換するアプリです。タブによるカテゴリー切り替え、計算式の表示、変換履歴の保存機能を備えています。
ソースコード
機能要件
-
長さの変換
- ミリメートル、センチメートル、メートル、キロメートル
- インチ、フィート、ヤード、マイル
- リアルタイム変換
- 計算式の表示
-
重さの変換
- ミリグラム、グラム、キログラム、トン
- オンス、ポンド
- リアルタイム変換
- 計算式の表示
-
温度の変換
- 摂氏、華氏、ケルビン
- 非線形変換の正確な処理
- 計算式の表示
-
変換履歴
- 変換結果の履歴保存(タイムスタンプ付き)
- LocalStorageでの永続化
- 履歴のクリア機能
実装ポイント
基準単位を介した変換
任意の単位間の変換を効率的に実装するため、「基準単位を介した2段階変換」のパターンを採用しています。まず入力値を基準単位(長さならメートル、重さならキログラム)に変換し、次に基準単位から目的の単位に変換します。この設計により、N個の単位間の変換を実装する際に、N²個の変換関数を用意する必要がなく、N個の変換係数だけで済みます。係数を設定ファイルで一元管理することで、新しい単位の追加が容易になります。
温度変換の特殊処理
温度変換は長さや重さと異なり、単純な比例関係ではないため、専用の変換ロジックが必要です。華氏から摂氏への変換には(°F - 32) × 5/9、摂氏から華氏への変換には°C × 9/5 + 32という異なる式が必要です。摂氏を基準単位とすることで、2段階変換のパターンを維持しながら、各温度スケールの特性に応じた正確な計算を実現しています。この設計により、コードの一貫性を保ちつつ、温度変換の複雑さを適切に処理できます。
浮動小数点演算の精度処理
JavaScriptの浮動小数点演算では丸め誤差が発生するため、単位変換の結果表示には適切な精度制御が必要です。このアプリではtoFixed()メソッドを使用して、用途に応じた精度で結果を表示しています。長さと重さの変換ではtoFixed(6)により小数点以下6桁まで表示し、ミリメートルやミリグラムのような小さな単位への変換でも十分な精度を確保しています。温度変換ではtoFixed(2)により小数点以下2桁に制限し、実用的な精度と可読性のバランスを保っています。この設計により、0.1 + 0.2が0.30000000000000004となるような浮動小数点の問題をユーザーに見せることなく、見やすい形式で結果を提示できます。
拡張アイディア
-
追加の単位カテゴリー
- 面積の変換(平方メートル、坪、エーカーなど)
- 体積の変換(リットル、ガロン、立方メートルなど)
- 速度の変換(km/h、m/s、mph、ノットなど)
- データ容量の変換(バイト、KB、MB、GBなど)
-
双方向リアルタイム変換
- 入力フィールドに入力すると即座に出力を更新
- 出力フィールドを編集すると逆変換
- デバウンス処理による最適化
学べること
-
数学的アルゴリズム
- 基準単位を介した効率的な変換パターン
- 線形変換と非線形変換の違い
- 精度を保つ浮動小数点演算(toFixedによる丸め処理)
- 用途に応じた適切な精度の選択
お絵描きアプリ
概要
Canvas APIを活用したお絵描きアプリです。ペンと消しゴムツールによる自由描画、色と線の太さの調整機能を備え、マウスとタッチ操作の両方に対応しています。
ソースコード
機能要件
-
描画機能
- ペンツールでの自由描画
- 色の選択・変更(カラーピッカー)
- 線の太さの調整(1px~50px)
- 消しゴムツールでの部分消去
- 全消去機能(確認ダイアログ付き)
-
保存機能
- PNG形式での画像保存
- プログラマティックなダウンロード
-
操作対応
- マウス操作(デスクトップ)
- タッチ操作(タブレット・スマートフォン)
- レスポンシブなキャンバスサイズ調整
実装ポイント
ペンツールでの自由描画
ペンツールでの自由描画は、マウス/タッチイベントと Canvas 2D API を組み合わせて実現しています。描画処理は3つのフェーズで構成されます。
-
描画開始(
startDrawing): マウスダウン/タッチスタート時に、開始点の座標を記録し、isDrawingフラグをtrueに設定します。開始点に小さな円を描画することで、クリックだけでも点が描けるようにしています(arcメソッドで線幅の半径の円を描画)。 -
描画中(
draw): マウスムーブ/タッチムーブ時に、前回の座標から現在の座標への線分を描画します。moveToで前回の位置に移動し、lineToで現在の位置まで線を引き、strokeでレンダリングします。座標を更新することで、連続した線を滑らかに描けます。 -
描画終了(
stopDrawing): マウスアップ/タッチエンド/マウスアウト時に、isDrawingフラグをfalseにして描画を停止します。
Canvas コンテキストの設定として、lineCap: 'round'とlineJoin: 'round'を指定することで、線の端と接続部を丸くし、自然な手描き感を実現しています。また、マウスとタッチの両方のイベントに対応することで、デスクトップとモバイル端末の両方で快適な描画体験を提供しています。座標の取得処理では、マウスイベントはoffsetX/Y、タッチイベントはgetBoundingClientRectとタッチ座標から相対位置を計算することで、統一的に扱えるようにしています。
消しゴム機能
Canvas APIのglobalCompositeOperationプロパティを使用して、消しゴム機能を実装しています。destination-outモードでは、描画した部分の既存のピクセルを透明にすることで消しゴム効果を実現します。通常のペンモードではsource-overを使用し、既存の描画の上に新しい描画を重ねます。この設計により、同じ描画ロジックを使いながら、モードの切り替えだけで異なる動作を実現できます。
画像保存機能
Canvas要素のtoDataURL()メソッドを使用して、描画内容をData URL形式(Base64エンコード)に変換しています。一時的なアンカー要素を作成してプログラマティックにクリックすることで、ユーザーにファイルをダウンロードさせています。
拡張アイディア
-
レイヤー機能
- 複数レイヤーの管理
- レイヤーの表示/非表示切り替え
- レイヤーの順序変更
- レイヤーごとの不透明度調整
-
図形描画ツール
- 直線、矩形、円、多角形の描画
- 塗りつぶし/輪郭のみの切り替え
- シフトキーで正円・正方形
-
テキスト挿入
- キャンバス上へのテキスト入力
- フォントサイズ・ファミリーの選択
- テキスト色の設定
-
Undo/Redo機能
- 描画履歴の保存
- 前の状態への復元
- やり直し機能
- 履歴のスタック管理
-
画像インポート
- 背景画像の読み込み
- 画像の上に描画
- 画像のリサイズと配置
-
ブラシバリエーション
- スプレー、エアブラシ効果
- パターンブラシ
- テクスチャブラシ
- ブラシの透明度設定
-
キャンバスサイズ調整
- カスタムサイズの指定
- プリセットサイズ(A4、正方形など)
- リサイズ時の描画内容保持
-
カラーパレット
- よく使う色の保存
- パレットのカスタマイズ
- 最近使った色の履歴
学べること
-
Canvas API基礎
- 2D描画コンテキストの取得と設定
- 線の描画(
moveTo、lineTo、stroke) - 円の描画(
arc) - 合成操作(
globalCompositeOperation) - Canvas座標系の理解
-
イベント処理
- マウスイベントとタッチイベントの統合
- イベント座標の取得と変換
- イベントリスナーの登録と解除
-
preventDefaultによるデフォルト動作の制御
-
ファイル操作
-
toDataURLによるCanvas内容の出力 - Data URLとBlob/Fileの理解
- プログラマティックなファイルダウンロード
-
電卓アプリ
概要
四則演算とパーセント計算が可能な電卓アプリです。キーボード操作にも対応し、ステートマシンパターンで実装された計算ロジックが特徴です。
ソースコード
機能要件
-
基本演算
- 四則演算(+, -, ×, ÷)
- パーセント計算(%)
- 小数点計算
-
操作機能
- 数字入力(0-9, 00, .)
- クリア(AC)
- バックスペース(DEL)
- イコール(=)
-
キーボード対応
- 数字キー(0-9)
- 演算子キー(+, -, *, /)
- Enterキーで計算実行
- Escapeキーでクリア
- Backspaceキーで1文字削除
-
表示機能
- 3桁カンマ区切り表示
- 浮動小数点演算の精度処理
実装ポイント
計算
連続計算をサポートしており、例えば「1 + 2 + 3 + ...」のように演算子を連続で押した場合にも、期待通りの計算結果が得られます。
拡張アイディア
-
科学計算機能
- 三角関数(sin, cos, tan)
- 対数、指数関数
- べき乗計算
-
計算履歴
- 過去の計算結果を履歴として保存
- 履歴から値を再利用
-
メモリ機能
- M+, M-, MR, MCボタン
- メモリに値を保存
学べること
-
複雑な状態管理
- ステートマシンパターン
- 複数の状態を持つアプリ設計
レシピ検索アプリ
概要
料理レシピを検索・閲覧できるアプリです。検索機能、カテゴリー・調理時間でのフィルタリング、モーダルでのレシピ詳細表示を備えた、複数条件でのデータフィルタリングを学べます。
ソースコード
機能要件
-
検索機能
- 料理名での検索
- 食材での検索
- タグでの検索
- リアルタイムフィルタリング
-
フィルタリング機能
- カテゴリー別フィルタリング(主菜、副菜、スープ、デザート)
- 調理時間によるフィルタリング(15分以内、30分以内、60分以内、60分超)
- 複数条件の組み合わせ
-
レシピ表示
- グリッドレイアウトでのレシピカード表示
- レシピカードクリックでモーダル表示
- 詳細情報(材料、手順、説明)の表示
実装ポイント
複数フィールドでの検索
検索語句を料理名、タグ、材料の3つのフィールドで検索することで、ユーザーが覚えている情報に応じて柔軟に検索できます。OR条件で結合することで、どのフィールドにマッチしても検索結果に含まれるようにしています。
条件付き表示
初期表示では全レシピを表示し、ユーザーが検索やフィルタリングを実行した後はフィルタリング結果のみを表示する設計です。ユーザーが何も操作していない状態と、検索結果が0件の状態を区別しています。
拡張アイディア
-
お気に入り機能
- レシピのお気に入り登録
- お気に入り一覧の表示
- LocalStorageでの永続化
-
並び替え機能
- 調理時間順のソート
- 人気順のソート
- 新着順のソート
-
レシピの追加・編集
- ユーザー独自のレシピ追加
- 既存レシピの編集機能
- 画像アップロード機能
学べること
-
複数条件フィルタリング
- AND条件での絞り込み
- 複数フィールドでの検索
- 条件の組み合わせロジック
- 大文字小文字を区別しない検索
マークダウンエディタアプリ
概要
リアルタイムプレビュー機能を備えたマークダウンエディタアプリです。テキスト入力と同時にHTMLプレビューを表示し、ツールバーによる書式設定支援、シンタックスハイライト、ファイルエクスポート機能を備えています。
ソースコード
機能要件
-
エディタ機能
- リアルタイムマークダウンプレビュー
- シンタックスハイライト対応(コードブロック)
- ツールバーによる書式設定支援(太字、斜体、見出し、リンク、画像、リスト、コード、引用、水平線)
- ローカルストレージでの自動保存・復元
- テキスト選択範囲を考慮した書式適用
-
エクスポート機能
- Markdownファイル (.md) として保存
- HTMLファイル (.html) として保存(スタイル付き)
- 両形式を同時ダウンロード
-
操作機能
- エディタ内容の全消去(確認ダイアログ付き)
- 選択テキストへの書式適用
- カーソル位置への書式挿入
実装ポイント
シンタックスハイライト
marked.jsとhighlight.jsを連携させることで、マークダウンのコードブロックに自動的にシンタックスハイライトを適用しています。コードブロックのレンダリング時にhighlight.jsの処理を挟み込んでいます。言語が指定されている場合(例: ```javascript)はhljs.highlight()で指定言語のハイライトを適用し、言語指定がない場合はhljs.highlightAuto()で自動判定を行います。この設計により、ユーザーが言語を指定しなくてもある程度適切なハイライトが適用されます。ハイライト結果のHTML文字列にはhljsクラスとlanguage-*クラスを付与することで、highlight.jsのCSSスタイルが適用されます。この二段階のクラス設定により、汎用スタイルと言語固有スタイルの両方を活用できます。セキュリティ面では、highlight.jsがHTMLエスケープを適切に処理するため、コード内の特殊文字がXSS攻撃に利用されることを防いでいます。
カーソル位置へのテキスト挿入
選択テキストがある場合は$1プレースホルダーを選択テキストで置換し、ない場合はそのままカーソル位置に挿入します。
ファイル保存処理
マークダウンファイルとHTMLファイルの2つを同時にダウンロードする実用的な機能です。Blob APIを使用してメモリ内でファイルを生成し、一時的なアンカー要素を作成してクリックすることでダウンロードを実行します。HTMLエクスポートでは、レンダリング済みのhtmlContentを完全なHTMLドキュメントに埋め込み、スタンドアロンで閲覧可能なファイルを生成しています。URL.revokeObjectURLでメモリリークを防いでいます。
dangerouslySetInnerHTML
マークダウンプレビューではdangerouslySetInnerHTMLを使用してHTMLをレンダリングしています。marked.jsは入力をサニタイズしてXSS攻撃を防ぐため、このアプリではユーザー自身が入力したマークダウンのみを扱うため安全です。外部ソースからのマークダウンを扱う場合は、追加のサニタイゼーション(DOMPurifyなど)が必要になります。
拡張アイディア
-
プレビュースクロール同期
- エディタとプレビューのスクロール位置を同期
- スクロール割合の計算と適用
- 双方向スクロール同期
-
マークダウンプレビューモード切り替え
- 編集モード、プレビューモード、分割モードの切り替え
- モバイル対応のタブ切り替え
- フルスクリーンモード
-
拡張書式サポート
- 表(テーブル)の挿入支援
- タスクリスト(チェックボックス)
- 絵文字ピッカー
- 数式表示(KaTeX、MathJax)
学べること
-
マークダウンパーサー連携
- marked.jsの設定とカスタマイズ
- カスタムレンダラーの実装
- GitHub Flavored Markdown対応
- 非同期パース処理
-
シンタックスハイライト
- highlight.jsの統合
- 言語自動検出
- カスタムレンダラーとの連携
- CSSスタイル適用
-
テキスト選択操作
- selectionStartとselectionEndの管理
- 選択範囲を考慮したテキスト挿入
- カーソル位置の判定
- 行頭判定ロジック
-
ファイル操作
- Blob APIでのファイル生成
- プログラマティックなダウンロード
- 複数形式でのエクスポート
- データURLの生成と解放
-
リアルタイムプレビュー
- 入力とプレビューの同期
- 非同期レンダリング処理
- パフォーマンス最適化
- dangerouslySetInnerHTMLの適切な使用
RSSリーダーアプリ
概要
RSS/Atomフィードを購読し、記事を統合表示するアプリです。XML解析、外部API連携、CORS対策などの実践的なWeb開発技術を学べます。
ソースコード
機能要件
-
フィード管理
- RSSフィードURLの追加
- フィードの削除
- フィード情報の表示(タイトル、説明)
- LocalStorageでのフィード永続化
-
記事表示
- 全フィードの記事を統合表示
- 記事の時系列ソート(新しい順)
- 記事情報の表示(タイトル、説明、公開日時、フィード名)
- 外部リンクへの遷移
-
フォーマット対応
- RSS 2.0フォーマットのパース
- Atom 1.0フォーマットのパース
- フォーマット自動判定
-
エラーハンドリング
- 無効なURLのチェック
- 重複フィードのチェック
- フィード取得失敗時のエラー表示
- XMLパースエラーの処理
実装ポイント
RSS/Atomパーサー
ブラウザ標準のDOMParserを使用してXMLを解析することで、外部ライブラリなしでRSS/Atomフィードを処理できます。RSS 2.0とAtom 1.0の両フォーマットに対応するため、それぞれのパーサー関数を実装し、XMLの要素構造の違いを適切に扱っています。querySelectorとquerySelectorAllでXML要素を取得し、必要な情報を抽出する設計により、シンプルで保守性の高いコードになっています。
CORS対策とフィード取得
CORS制限を回避するために、AllOrigins APIをプロキシサービスとして使用しています。これにより、クライアントサイドから任意のRSSフィードを取得できます。DOMParserでXMLをパースした後、parsererror要素の有無をチェックすることで、XML形式の妥当性を検証しています。エラーハンドリングを適切に実装することで、ネットワークエラーやパースエラーをユーザーに分かりやすく伝えられます。
フォーマット自動判定
XMLドキュメントからchannel要素(RSS)またはfeed要素(Atom)の存在を確認することで、フォーマットを自動判定しています。この設計により、ユーザーはフィードの種類を意識することなく、どちらの形式でも同じように扱えます。
記事の統合とソート
複数のフィードから取得した記事を1つの配列に統合し、公開日時でソートすることで、すべてのフィードの最新記事を時系列で表示できます。各記事にフィードのタイトルを追加することで、どのフィードからの記事かを識別可能にしています。個別のフィード取得エラーが全体の処理を止めないよう、try-catchで適切にエラーハンドリングしています。
HTMLサニタイゼーション
RSS記事の説明文にはHTMLタグが含まれていることが多いため、一時的なDOM要素を作成してHTMLをパースし、テキストコンテンツのみを抽出しています。この方法により、XSS攻撃のリスクを軽減しながら、安全に記事を表示できます。日付のフォーマット処理では、無効な日付文字列に対してもエラーを発生させず、元の文字列を返すフォールバック処理を実装しています。
拡張アイディア
-
既読管理
- 記事の既読/未読状態を管理
- 未読記事のカウント表示
- 既読記事のマーク表示
-
フィルタリング機能
- フィード別の記事表示
- キーワード検索
- 日付範囲でのフィルター
-
更新機能
- 自動更新(定期的なフィード取得)
- 手動更新ボタン
- 最終更新時刻の表示
-
お気に入り機能
- 記事のお気に入り登録
- お気に入り記事の一覧表示
- お気に入りの永続化
-
カテゴリー管理
- フィードのカテゴリー分類
- カテゴリー別表示
- カテゴリーの色分け
-
エクスポート/インポート
- OPMLフォーマットでのエクスポート
- 他のRSSリーダーからのインポート
- フィードリストのバックアップ
学べること
-
XML処理
- DOMParserの使用方法
- XMLドキュメントのクエリと解析
- RSS/Atomフォーマットの理解
-
CORS対策
- CORS制限の仕組み
- プロキシサービスの活用
- APIキーなしのパブリックプロキシ利用
-
非同期処理
- async/awaitパターン
- 複数の非同期処理の管理
- エラーハンドリングのベストプラクティス
-
セキュリティ
- HTMLサニタイゼーション
- XSS対策
- 外部コンテンツの安全な表示
タイムゾーン変換アプリ
概要
世界中のタイムゾーン間で時刻を変換するアプリです。リアルタイムで更新される世界時計機能も搭載し、国際化対応しています。
ソースコード
機能要件
-
タイムゾーン変換
- 任意の時刻を入力
- 変換元と変換先のタイムゾーンを選択
- 変換結果を表示(時刻、日付、曜日)
-
現在時刻設定
- ワンクリックで現在時刻を入力
- 自動的に変換を実行
-
世界時計
- 主要都市の現在時刻をリアルタイム表示
- 1秒ごとに自動更新
- 日付と曜日も表示
実装ポイント
タイムゾーン変換
Intl.DateTimeFormatを使用することで、ブラウザ標準の国際化APIを活用し、クロスブラウザでの互換性を確保しています。タイムゾーン間の変換を正確に処理することで、サマータイムなどの複雑なルールにも自動的に対応できます。外部ライブラリに依存しない実装により、バンドルサイズを小さく保ちながら、十分な機能を提供しています。
リアルタイム世界時計
setIntervalを使って1秒ごとに時刻を更新することで、リアルタイムに時計を動作させています。useEffectのクリーンアップ関数でclearIntervalを呼び出すことにより、コンポーネントのアンマウント時にタイマーを確実に停止し、メモリリークを防止します。複数都市の時刻を一括で取得する設計により、パフォーマンスを最適化しながら、ユーザーに同期した世界時計を提供できます。
日時入力とフォーマット
HTML5のdatetime-local入力形式に準拠することで、標準的なブラウザのDateTimeピッカーを活用し、一貫したユーザー体験を提供しています。padStartメソッドでゼロパディングを行うことにより、必ず2桁の表示形式を維持し、フォーマットの統一性を保ちます。ユーザーの現在時刻を取得する機能により、デフォルト値として現在時刻を設定でき、利便性を高めています。
拡張アイディア
-
タイムゾーン検索
- 都市名や国名で検索
- オートコンプリート機能
-
お気に入り機能
- よく使うタイムゾーンを保存
- クイックアクセス
-
会議時間調整
- 複数のタイムゾーンを並べて表示
- 全員の営業時間内を自動で提案
-
サマータイム対応表示
- サマータイム適用状況を表示
- 切り替わり日時の通知
-
カレンダー連携
- Google CalendarなどのAPIと連携
- イベント時刻を自動変換
学べること
-
国際化(i18n)
-
Intl.DateTimeFormatの活用 - タイムゾーンの扱い
- 日付・時刻のローカライズ
-
-
リアルタイム処理
- setIntervalを使った定期更新
- パフォーマンスを考慮した更新処理
-
日付・時刻の計算
- Dateオブジェクトの操作
- タイムゾーン変換の仕組み
読書記録アプリ
概要
書籍の読書履歴を管理するアプリです。本の登録、検索、フィルタリング、統計表示、月別のグラフ表示機能を備えています。
ソースコード
機能要件
-
書籍管理
- 書籍の追加(タイトル、著者、ジャンル、読書開始日、終了日、評価、レビュー)
- 書籍の編集(モーダル経由で既存データを修正)
- 書籍の削除(確認ダイアログ付き)
- 詳細表示(モーダルで全情報を表示)
-
検索・フィルタリング
- テキスト検索(タイトル・著者名でリアルタイム検索)
- ジャンル別フィルタ(小説、ビジネス、自己啓発、科学、歴史、その他)
- ソート機能(日付順、タイトル順、評価順)
-
統計表示
- 総読書冊数
- 今月の読書冊数
- 最多ジャンル
- 平均評価
- 月別読書グラフ(過去6ヶ月の棒グラフ)
実装ポイント
Chart.jsによるデータ可視化
Chart.jsとreact-chartjs-2を組み合わせることで、Reactのデータフローに沿った形でグラフを実装できます。必要なコンポーネントのみを登録するTree-shaking対応により、バンドルサイズを抑えています。月別データを視覚化することで、ユーザーの読書習慣をひと目で把握でき、モチベーション向上にもつながります。
拡張アイディア
-
書籍API連携
- Google Books APIなどで書籍情報を自動取得
- ISBNから書籍データを補完
- 表紙画像の表示
-
タグ機能
- 書籍に複数のタグを付与
- タグクラウド表示
- タグでのフィルタリング
-
読書目標設定
- 月間・年間の目標冊数を設定
- 進捗率の可視化
- 達成状況の通知
-
エクスポート機能
- CSV形式でデータをエクスポート
- JSON形式でバックアップ
- 読書レポートのPDF生成
学べること
-
データ可視化
- Chart.jsの統合
- 統計データの計算と表示
- グラフコンポーネントの実装
家計簿アプリ
概要
収入と支出を管理する家計簿アプリです。取引の記録、月別・カテゴリ別フィルタリング、カテゴリ別支出のドーナツチャート表示機能を備えています。
ソースコード
機能要件
-
取引管理
- 取引の追加(日付、内容、金額、タイプ、カテゴリ)
- 取引の編集(既存データを修正)
- 取引の削除
- 収入・支出の切り替え
-
カテゴリ管理
- 収入カテゴリ(給料、副業、その他)
- 支出カテゴリ(食費、交通費、娯楽、光熱費、通信費、医療費、その他)
- カテゴリ別フィルタリング
-
サマリー表示
- 総収入の表示
- 総支出の表示
- 残高の計算と表示(プラス/マイナスで色分け)
-
フィルタリング
- 月別フィルタ(YYYY-MM形式)
- カテゴリ別フィルタ
- フィルタ適用ボタン
-
データ可視化
- カテゴリ別支出のドーナツチャート
- パーセント表示
- 円グラフで支出の内訳を視覚化
実装ポイント
フィルタ管理
フィルタの入力状態と適用済みフィルタを分離することで、ユーザーがフィルタを変更してもすぐには反映されず、「適用」ボタンを押した時のみフィルタリングが実行される設計になっています。これにより、ユーザーは複数の条件を設定してから一度に適用でき、パフォーマンスも最適化されます。デフォルトで現在の月を設定することで、ユーザビリティを向上させています。
Chart.jsによる支出可視化
Chart.jsとreact-chartjs-2を使用してドーナツチャートを実装し、カテゴリ別の支出を視覚的に表現しています。支出データのみをフィルタリングし、カテゴリごとに金額を集計することで、ユーザーの支出パターンを明確に示します。ツールチップでは金額と割合の両方を表示し、Intl.NumberFormatで日本円形式にフォーマットすることで、ユーザーフレンドリーな表示を実現しています。
拡張アイディア
-
予算設定機能
- カテゴリごとに月間予算を設定
- 予算に対する実績の進捗表示
- 予算超過時のアラート
-
収支レポート
- 月次・年次の収支レポート
- 収入と支出の推移グラフ(折れ線グラフ)
- 前月比・前年比の表示
-
領収書管理
- 取引に画像を添付
- OCRで領収書の金額を自動読み取り
- クラウドストレージ連携
-
目標貯蓄機能
- 貯蓄目標を設定
- 目標までの残り金額と期間を表示
- 月次の貯蓄推移グラフ
-
CSV/PDFエクスポート
- 取引データのCSVエクスポート
- 収支レポートのPDF出力
- 確定申告用データの出力
学べること
-
Chart.jsによるデータ可視化
- ドーナツチャートの実装
- データの集計と整形
- カスタムツールチップの実装
- レスポンシブなチャート表示
-
フィルタリングロジック
- 複数条件の組み合わせ
- 適用前フィルタと適用後フィルタの分離
- パフォーマンスを考慮した設計
-
金額フォーマット処理
- Intl.NumberFormatの活用
- 通貨表示の国際化対応
- プラス/マイナスの視覚的表現
カレンダーアプリ
概要
月間カレンダー表示とイベント管理機能を備えた本格的なスケジュール管理アプリです。日付計算、イベントのCRUD操作、モーダルUI、複雑な状態管理が学べます。
ソースコード
機能要件
-
月間カレンダー表示
- 6週×7日の42日グリッド表示
- 前月・次月の日付を含む完全なカレンダービュー
- 今日の日付を特別なスタイルでハイライト
- 月内の日付と月外の日付を視覚的に区別
-
カレンダー操作
- 前月・次月への移動
- 今日の日付へジャンプ
- 日付クリックでイベント作成モーダルを表示
-
イベント管理
- イベントの追加(タイトル必須、時刻・詳細は任意)
- イベントの編集(サイドバーから編集)
- イベントの削除(確認ダイアログ付き)
- カレンダー上に最大3件のイベントを表示(超過分は「他 X 件」表示)
-
イベント一覧
- サイドバーに今日以降のイベントを時系列表示
- 日付でグルーピング
- 編集・削除ボタンでクイックアクセス
- イベントなしの場合の空状態メッセージ
実装ポイント
42日グリッド生成
カレンダーアプリの核となる42日グリッド生成ロジックです。月の最初の曜日から逆算して前月の日付を含めることで、視覚的に完全なカレンダーを実現しています。各日付に対して、現在月か、今日か、どのイベントがあるかの情報を持たせることで、CalendarDayコンポーネントが適切なスタイルと内容を表示できます。この設計により、カレンダーのレンダリングロジックとビジネスロジックが明確に分離されています。
カレンダー日表示
各カレンダーセル内で最大3件のイベントを表示し、超過分は「他 X 件」として表示することで、UIの混雑を防いでいます。条件付きクラス名を使用して、現在月外の日付、今日の日付に異なるスタイルを適用し、視覚的な区別を明確にしています。イベントの時刻がある場合のみ表示する設計により、柔軟なイベント表示を実現しています。
拡張アイディア
-
週表示・日表示
- 月表示に加えて週単位・日単位の表示モード
- 詳細な時間軸表示(30分刻み)
- ドラッグ&ドロップでイベント作成
-
繰り返しイベント
- 毎日、毎週、毎月の繰り返し設定
- 繰り返しの終了条件(日付指定、回数指定)
- 個別の繰り返しイベントの編集・削除
-
カテゴリー・色分け
- イベントにカテゴリーを設定
- カテゴリーごとに色分け表示
- カテゴリーフィルタ機能
-
リマインダー・通知
- イベント開始前の通知設定
- ブラウザ通知API連携
- メール通知(バックエンド連携)
-
他カレンダーとの連携
- Google Calendar API連携
- iCalendar形式のインポート/エクスポート
- 他のカレンダーサービスとの同期
-
ドラッグ&ドロップ
- イベントのドラッグ移動
- 日付間でのイベント移動
- 時間の調整(週表示・日表示で)
-
検索機能
- イベントタイトルでの検索
- 日付範囲での検索
- カテゴリーでのフィルタリング
学べること
-
複雑な日付計算
- カレンダーグリッドの生成ロジック
- 前月・次月の日付を含む計算
- 曜日の取得と配置
- 今日の判定ロジック
-
高度な状態管理
- Record型を使ったインデックス管理
- 日付キーでのデータ構造設計
- 複数の状態の協調管理
-
日付ユーティリティ
- 日付フォーマット処理
- 日付の比較と判定
- タイムゾーンを考慮しない日付処理
画像エディタアプリ
概要
ブラウザベースの画像編集アプリです。色調整、フィルター効果、変形操作、リサイズ機能を備えた、HTML5 Canvas APIを活用しています。
ソースコード
機能要件
-
色調整機能 (非破壊編集)
- 明るさ調整(-100〜+100)
- コントラスト調整(-100〜+100)
- 彩度調整(-100〜+100)
- リアルタイムプレビュー
-
フィルター効果
- オリジナル(フィルターなし)
- モノクロ(Grayscale)
- セピア(Sepia)
- 反転(Invert)
- ぼかし(Blur)
-
変形操作 (Canvas ベース)
- 左回転・右回転(90度単位)
- 水平反転
- 垂直反転
-
リサイズ機能
- 幅・高さの個別入力(px単位)
- 縦横比維持オプション
- 手動サイズ調整
-
ファイル操作
- 画像アップロード(ファイル入力)
- 編集画像のダウンロード(PNG形式)
- オリジナル画像へのリセット
実装ポイント
Canvas APIによる画像読み込みと描画
画像エディタの基本となる画像読み込みでは、FileReader APIとCanvas APIを組み合わせています。ユーザーが選択した画像ファイルをFileReaderで読み込み、Data URLに変換した後、Imageオブジェクトを作成してonloadイベントで画像データを取得します。画像が読み込まれたら、Canvasのサイズを画像の実サイズに合わせて設定(canvas.width = img.width; canvas.height = img.height)し、ctx.drawImage(img, 0, 0)で画像をCanvasに描画します。この時点でCanvasには元画像がピクセルデータとして保存され、以降の編集操作の基盤となります。
元画像と編集中の画像を別々のImageオブジェクトとして管理することで、リセット機能を簡単に実装できます。canvas.toDataURL()を使用してCanvasの内容をData URL形式に変換し、それをImageオブジェクトのsrcに設定することで、編集後の画像を保持します(useImageEditor.ts:32-74)。
Canvas API座標変換による回転・反転
回転と反転の実装では、Canvas APIの座標変換機能(translate、rotate、scale)を活用しています。これらの操作は破壊的な変更となるため、ctx.save()とctx.restore()で変換マトリックスの状態を保存・復元することが重要です。
回転処理のフローは次の通りです:
-
ctx.clearRect()でCanvasをクリア -
ctx.save()で現在の描画状態を保存 -
ctx.translate(canvas.width / 2, canvas.height / 2)で原点をCanvasの中心に移動 -
ctx.rotate(editState.rotation * Math.PI / 180)で指定角度だけ回転 -
ctx.scale(editState.flipX ? -1 : 1, editState.flipY ? -1 : 1)で反転を適用 -
ctx.drawImage()で画像を描画(中心を基準に配置するため座標をマイナス値で指定) -
ctx.restore()で描画状態を復元
この設計により、回転と反転を組み合わせた複雑な変形も、座標変換の組み合わせとして直感的に実装できます。角度はラジアン単位で指定する必要があるため、度数法からの変換(* Math.PI / 180)を行っています。
Canvas Filter APIによる色調整
色調整とフィルター効果の実装には、Canvas要素のstyle.filterプロパティにCSSフィルターを適用する方法を採用しています。これは非破壊編集として機能し、リアルタイムプレビューに最適です。
フィルター文字列は、複数のフィルター関数を空白区切りで連結することで組み合わせられます(useImageEditor.ts:123-157):
filterString += `brightness(${100 + editState.brightness}%) `;
filterString += `contrast(${100 + editState.contrast}%) `;
filterString += `saturate(${100 + editState.saturation}%) `;
ベースを100%とし、-100〜+100の調整値を加算することで、0%〜200%の範囲で調整できます。フィルター効果(モノクロ、セピア、反転、ぼかし)は、対応するCSS filter関数を追加することで実現します。この方法の利点は、GPU加速により高速に処理されることと、元の画像データを変更せずにプレビューできることです。編集を確定する際は、一時的なcanvas要素を作成し、tempCtx.filterにフィルター文字列を設定してからdrawImageすることで、フィルター効果を実際のピクセルデータに焼き込みます(useImageEditor.ts:159-199)。
Canvas APIによるリサイズ処理
リサイズ機能では、drawImageの引数を活用してスケーリングを実現しています。drawImage(image, 0, 0, newWidth, newHeight)のように描画サイズを指定することで、Canvas APIが自動的に画像を拡大・縮小します。
縦横比維持機能は、元画像のアスペクト比を計算し、一方の値が変更されたら他方を自動的に調整するロジックで実装しています(useImageEditor.ts:239-257):
const ratio = originalImageRef.current.height / originalImageRef.current.width;
setDimensions({ width: newDimensions.width, height: Math.round(newDimensions.width * ratio) });
リサイズを適用する際は、まず現在の編集内容を焼き込み、その後新しいサイズでCanvasを再作成して画像を描画し直します(useImageEditor.ts:259-277)。Math.round()で整数値に丸めることで、ピクセル単位での正確な描画を保証しています。
二段階処理パイプライン
二段階の処理パイプラインを採用することで、編集操作を効率化しています。第一段階ではCSSフィルターを使用して高速なリアルタイムプレビューを提供し、第二段階では一時キャンバスを使ってフィルターを実際の画像データに焼き込みます。この設計により、変形操作(回転・反転)とフィルター効果を正しく組み合わせられます。状態をリセットすることで、同じフィルターが二重に適用されることを防いでいます。
Ref Forwarding パターン
forwardRefとuseImperativeHandleを組み合わせて、Canvasコンポーネントから親コンポーネントに対してCanvas要素とContextへのアクセスを公開しています(Canvas.tsx:14-20)。この設計により、コンポーネントのカプセル化を保ちつつ、必要な操作を親から実行できます。onCanvasReadyコールバックを使用することで、Canvas要素が利用可能になったタイミングを親に通知し、初期化処理を適切に実行できます。
拡張アイディア
-
レイヤー機能
- 複数の画像レイヤーの管理
- レイヤーの順序変更、不透明度調整
- レイヤーごとの編集と合成
-
描画ツール
- フリーハンド描画(ペン、ブラシ)
- 図形描画(矩形、円、線)
- テキスト挿入機能
- 消しゴムツール
-
クロップ機能
- ドラッグ&ドロップでのクロップ範囲選択
- アスペクト比固定クロップ
- 自由形状クロップ
-
フィルター追加
- シャープネス、ノイズリダクション
- ヴィネット効果
- カスタムフィルターの作成
- フィルタープリセットの保存
-
編集履歴
- Undo/Redo機能
- 編集履歴のビジュアル表示
- 特定の状態への復元
-
バッチ処理
- 複数画像の一括処理
- 同一フィルターの一括適用
- 一括リサイズ・フォーマット変換
-
エクスポート形式
- JPEG、PNG、WebP形式対応
- 品質設定オプション
- メタデータの保持・編集
学べること
-
Canvas API基礎
- 2D Contextの取得と設定
- Canvasサイズの動的設定
-
drawImageによる画像描画(3種類の引数パターン) -
toDataURLによるCanvas内容のエクスポート
-
Canvas API座標変換
-
translateによる座標系の移動 -
rotateによる回転(ラジアン単位) -
scaleによる拡大縮小・反転 -
save/restoreによる描画状態の管理 - 変換マトリックスの組み合わせ
-
-
Canvas Filter API
- CSSフィルターの適用(
style.filter) - 複数フィルターの組み合わせ
- GPU加速を利用した高速処理
- 一時Canvasを使ったフィルター焼き込み
- CSSフィルターの適用(
-
FileReader API
- ファイル読み込みと非同期処理
- Data URLへの変換
- Imageオブジェクトとの連携
-
高度な Ref 操作
- forwardRefとuseImperativeHandle
- 複数のRefの管理(canvas、image)
- Ref経由でのDOM操作
- コンポーネント間のAPI設計
-
画像処理パイプライン
- 非破壊編集の実装
- CSSフィルターとCanvas処理の組み合わせ
- 一時キャンバスを使った処理の焼き込み
- 元画像と編集画像の分離管理
まとめ
各アプリの完成度が高いため、実務で使えるパターンも多く含まれています。自分のレベルに合ったアプリから始めて、じっくり取り組むことで、Reactの実践力を確実に身につけることができます。