React NativeのTodoアプリで実装する相対時間ベースのプリセット機能

はじめに Todoアプリを使っていると、毎日・毎週繰り返す定型タスクの登録が面倒に感じることはありませんか? 「毎朝のルーチン」「週次ミーティングの準備タスク」など、同じタスクセットを何度も手入力するのは非効率です。この記事では、相対時間を使ったプリセット機能の実装方法を紹介します。 実装したアプリのソースコード: https://github.com/your-repo (適宜修正してください) 問題:絶対時間で期限を保存すると使い回せない 一般的なTodoアプリでプリセット機能を実装する場合、以下のような設計になりがちです: // ❌ よくある実装(絶対時間) interface PresetTask { text: string; dueDate: Date; // 2026-02-08 09:00:00 } この設計の問題点: プリセット作成時の日時が保存される 翌日読み込むと「昨日の9時」が期限になってしまう 毎回手動で期限を修正する必要がある 解決策:相対時間(dueHoursOffset)で管理する 代わりに、「今から何時間後」という相対的な時間で期限を管理します: // ✅ 相対時間ベースの設計 export interface PresetTask { id: string; text: string; priority?: Priority; dueHoursOffset?: number; // 現在時刻からの相対時間(時間単位) checklist?: string[]; } export interface Preset { id: string; name: string; tasks: PresetTask[]; createdAt: Date; } 公式ドキュメント: date-fns addHours: https://date-fns.org/v4.1.0/docs/addHours 実装の全体像 1. プリセット作成時の実装 プリセット編集画面では、期限を「現在時刻から何時間後」として入力します: // screens/PresetEditScreen.tsx const TaskInputRow = ({ item, index, onTaskTextChange, onDueHoursOffsetChange, // ... }: { item: PresetTask; index: number; onTaskTextChange: (index: number, text: string) => void; onDueHoursOffsetChange: (index: number, value: string) => void; // ... }) => { return ( <Card style={styles.taskCard}> <View style={styles.taskInputRow}> <TextInput label={`タスク ${index + 1}`} value={item.text} onChangeText={text => onTaskTextChange(index, text)} mode="outlined" style={styles.taskTextInput} autoComplete="off" autoCorrect={false} /> <TextInput label="期限(時間)" value={item.dueHoursOffset?.toString() || ''} onChangeText={value => { // 数字以外を除去 const filteredValue = value.replace(/[^0-9]/g, ''); onDueHoursOffsetChange(index, filteredValue); }} keyboardType="numeric" mode="outlined" style={styles.dueOffsetInput} /> </View> {/* ... */} </Card> ); }; ポイント: ...

February 8, 2026 · 4 min