取り組みの背景 — カレンダーアプリを作って学ぼう
スケジュール管理アプリは、日常的に使われるアプリの中でも特に人気のあるジャンルです。予定の追加・編集・表示・リマインダーといった機能を実装する過程で、状態管理、データの永続化、UIコンポーネントの設計など、アプリ開発の基本をバランスよく学ぶことができます。
ここではRork を使ってカレンダー・スケジュール管理アプリをゼロから構築する方法をご紹介します。プログラミングの経験が少ない方でも、Rork の AI アシスタントに適切なプロンプトを渡すことで、本格的なアプリを短時間で形にできます。
この記事で学べること:
- カレンダーUI の基本構造と月表示・週表示の切り替え
- 予定データの管理(追加・編集・削除)
- AsyncStorage を使ったローカルデータの保存
- プッシュ通知によるリマインダー機能の基礎
- App Store / Google Play に提出できるレベルのUI仕上げ
Rork に初めて触れる方は、まず「Rork をはじめよう — 初心者ガイド」に目を通しておくとスムーズです。
前提知識・環境準備
必要なもの
- Rork アカウント(無料プランでも基本機能は使えます)
- スマートフォン(iOS または Android — Expo Go でプレビュー確認)
- PC のブラウザ(Rork のエディタにアクセスするため)
あると望ましい知識
- HTML / CSS の基本的な理解
- JavaScript の変数・関数・配列の概念
とはいえ、Rork は AI がコードを生成してくれるので、これらの知識が不十分でも大丈夫です。分からない部分は Rork のチャットで「この部分を説明して」と聞けば、丁寧に教えてくれます。
ステップ 1: プロジェクトを作成する
Rork のダッシュボードにログインし、「New Project」をクリックします。プロジェクト名は my-calendar-app など、分かりやすい名前を付けましょう。
最初のプロンプトとして、以下のように入力します。
カレンダー・スケジュール管理アプリを作ってください。
以下の機能を含めてください:
1. 月表示のカレンダーUI(今日の日付をハイライト)
2. 日付をタップすると、その日の予定一覧を表示
3. 予定の追加フォーム(タイトル、開始時刻、終了時刻、メモ)
4. 予定の編集と削除
5. AsyncStorage でデータをローカル保存
6. モダンでクリーンなデザイン(カラーテーマ: ブルー系)Rork がこのプロンプトを元に、画面構成・コンポーネント・ナビゲーションを自動生成します。数分待つとプレビューが表示されるので、Expo Go アプリでスキャンして実機確認しましょう。
ステップ 2: カレンダーUI を構築する
Rork が生成するカレンダーコンポーネントは、通常 react-native-calendars ライブラリをベースにしています。月表示のカレンダーに予定のドットマーカーを表示する基本的なコードは以下のようになります。
// CalendarScreen.tsx — カレンダーメイン画面
import React, { useState, useMemo } from 'react';
import { View, StyleSheet } from 'react-native';
import { Calendar } from 'react-native-calendars';
type Event = {
id: string;
title: string;
date: string; // 'YYYY-MM-DD'
startTime: string;
endTime: string;
memo: string;
};
type Props = {
events: Event[];
onDayPress: (dateString: string) => void;
};
export default function CalendarScreen({ events, onDayPress }: Props) {
const [selectedDate, setSelectedDate] = useState('');
// 予定がある日付にドットマーカーを付ける
const markedDates = useMemo(() => {
const marks: Record<string, any> = {};
events.forEach((event) => {
marks[event.date] = {
...marks[event.date],
marked: true,
dotColor: '#4A90D9',
};
});
if (selectedDate) {
marks[selectedDate] = {
...marks[selectedDate],
selected: true,
selectedColor: '#4A90D9',
};
}
return marks;
}, [events, selectedDate]);
const handleDayPress = (day: { dateString: string }) => {
setSelectedDate(day.dateString);
onDayPress(day.dateString);
};
return (
<View style={styles.container}>
<Calendar
markedDates={markedDates}
onDayPress={handleDayPress}
theme={{
todayTextColor: '#4A90D9',
arrowColor: '#4A90D9',
monthTextColor: '#333',
textDayFontSize: 16,
textMonthFontSize: 18,
textDayHeaderFontSize: 14,
}}
/>
</View>
);
}
// 期待される出力:
// 月表示のカレンダーが表示され、予定がある日付にはブルーのドットが表示される。
// 日付をタップすると選択状態(ブルーの背景)になり、その日の予定一覧が下部に表示される。
const styles = StyleSheet.create({
container: {
backgroundColor: '#FFFFFF',
borderRadius: 12,
overflow: 'hidden',
margin: 16,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
});ポイントは markedDates を useMemo で効率的に計算している点です。予定データが変わるたびにカレンダーのマーカーが自動更新されます。
ステップ 3: 予定の追加・編集フォームを作る
次に、予定を入力するためのフォーム画面を実装します。Rork にこのように指示しましょう。
予定追加フォームを作ってください:
- タイトル(必須、テキスト入力)
- 日付(DateTimePicker で選択)
- 開始時刻・終了時刻(TimePicker で選択)
- メモ(任意、複数行テキスト入力)
- 「保存」ボタンと「キャンセル」ボタン
- バリデーション:タイトルが空の場合はエラーメッセージを表示生成されるフォームのコア部分は、以下のような構造になります。
// AddEventForm.tsx — 予定追加フォーム(コア部分)
import React, { useState } from 'react';
import {
View, Text, TextInput, TouchableOpacity,
Alert, StyleSheet, ScrollView,
} from 'react-native';
type EventInput = {
title: string;
date: string;
startTime: string;
endTime: string;
memo: string;
};
type Props = {
initialDate: string;
onSave: (event: EventInput) => void;
onCancel: () => void;
};
export default function AddEventForm({ initialDate, onSave, onCancel }: Props) {
const [title, setTitle] = useState('');
const [memo, setMemo] = useState('');
const [startTime, setStartTime] = useState('09:00');
const [endTime, setEndTime] = useState('10:00');
const handleSave = () => {
if (!title.trim()) {
Alert.alert('入力エラー', 'タイトルを入力してください');
return;
}
onSave({
title: title.trim(),
date: initialDate,
startTime,
endTime,
memo: memo.trim(),
});
};
return (
<ScrollView style={styles.container}>
<Text style={styles.label}>タイトル *</Text>
<TextInput
style={styles.input}
value={title}
onChangeText={setTitle}
placeholder="会議、ランチ、勉強会..."
/>
<Text style={styles.label}>開始時刻</Text>
<TextInput
style={styles.input}
value={startTime}
onChangeText={setStartTime}
placeholder="09:00"
/>
<Text style={styles.label}>終了時刻</Text>
<TextInput
style={styles.input}
value={endTime}
onChangeText={setEndTime}
placeholder="10:00"
/>
<Text style={styles.label}>メモ</Text>
<TextInput
style={[styles.input, styles.memoInput]}
value={memo}
onChangeText={setMemo}
placeholder="詳細メモ(任意)"
multiline
numberOfLines={4}
/>
<View style={styles.buttonRow}>
<TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
<Text style={styles.cancelText}>キャンセル</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.saveButton} onPress={handleSave}>
<Text style={styles.saveText}>保存</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
}
// 期待される出力:
// タイトル・時刻・メモを入力できるフォームが表示される。
// 「保存」をタップするとバリデーション後にデータが保存される。
// タイトルが空の場合は「タイトルを入力してください」とアラートが表示される。
const styles = StyleSheet.create({
container: { padding: 20 },
label: { fontSize: 14, fontWeight: '600', color: '#555', marginTop: 16, marginBottom: 6 },
input: {
borderWidth: 1, borderColor: '#DDD', borderRadius: 8,
padding: 12, fontSize: 16, backgroundColor: '#FAFAFA',
},
memoInput: { height: 100, textAlignVertical: 'top' },
buttonRow: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 24 },
cancelButton: {
flex: 1, marginRight: 8, padding: 14, borderRadius: 8,
borderWidth: 1, borderColor: '#DDD', alignItems: 'center',
},
cancelText: { fontSize: 16, color: '#666' },
saveButton: {
flex: 1, marginLeft: 8, padding: 14, borderRadius: 8,
backgroundColor: '#4A90D9', alignItems: 'center',
},
saveText: { fontSize: 16, color: '#FFF', fontWeight: '600' },
});ステップ 4: AsyncStorage でデータを保存する
アプリを閉じても予定データが消えないよう、AsyncStorage を使ってローカル保存を実装します。
// storage.ts — データ永続化ユーティリティ
import AsyncStorage from '@react-native-async-storage/async-storage';
const EVENTS_KEY = '@calendar_events';
export type CalendarEvent = {
id: string;
title: string;
date: string;
startTime: string;
endTime: string;
memo: string;
};
// 全予定を読み込む
export async function loadEvents(): Promise<CalendarEvent[]> {
try {
const json = await AsyncStorage.getItem(EVENTS_KEY);
return json ? JSON.parse(json) : [];
} catch (error) {
console.error('Failed to load events:', error);
return [];
}
}
// 予定を保存する
export async function saveEvents(events: CalendarEvent[]): Promise<void> {
try {
await AsyncStorage.setItem(EVENTS_KEY, JSON.stringify(events));
} catch (error) {
console.error('Failed to save events:', error);
}
}
// 予定を1件追加する
export async function addEvent(
event: Omit<CalendarEvent, 'id'>
): Promise<CalendarEvent> {
const events = await loadEvents();
const newEvent: CalendarEvent = {
...event,
id: Date.now().toString(),
};
events.push(newEvent);
await saveEvents(events);
return newEvent;
}
// 予定を削除する
export async function deleteEvent(id: string): Promise<void> {
const events = await loadEvents();
const filtered = events.filter((e) => e.id !== id);
await saveEvents(filtered);
}
// 期待される出力:
// loadEvents() → 保存済みの予定配列を返す(初回は空配列)
// addEvent({...}) → 新しいIDを付与して保存し、追加した予定オブジェクトを返す
// deleteEvent('123') → 該当IDの予定を削除して再保存するRork でこのような永続化パターンを使うことで、アプリを再起動しても予定データが保持されます。将来的に Supabase や Firebase と連携してクラウド同期に拡張することも可能です。
ステップ 5: リマインダー通知を追加する
ユーザーが予定の時刻前にリマインダーを受け取れるよう、プッシュ通知機能を追加しましょう。Rork に以下のように伝えます。
予定の15分前にローカル通知でリマインダーを送る機能を追加してください。
Expo Notifications を使い、予定の保存時に自動でスケジュールしてください。プッシュ通知の実装については、「Rork でプッシュ通知を実装する」でさらに詳しく解説していますので、あわせてご覧ください。
よくあるエラーと対処法
カレンダーが表示されない
react-native-calendars のインストールが正しく行われていない可能性があります。Rork のターミナルで npx expo install react-native-calendars を実行してみてください。
予定を保存してもアプリ再起動で消える
AsyncStorage が正しくインポートされているか確認しましょう。@react-native-async-storage/async-storage パッケージがインストール済みであることを package.json で確認してください。
DateTimePicker が iOS と Android で見た目が異なる
これは React Native の仕様です。@react-native-community/datetimepicker はプラットフォームごとにネイティブ UI を使うため、統一したい場合はカスタムモーダルを作成するよう Rork に依頼しましょう。
応用・発展的な活用法
基本のカレンダーアプリが完成したら、以下のような機能を追加して差別化を図りましょう。
週表示・日表示の切り替え: 月表示だけでなく、週表示や日表示のタイムライン(時間軸で予定を表示)を追加すると、より本格的なスケジュール管理アプリになります。
カテゴリ分けとカラーコーディング: 「仕事」「プライベート」「健康」などのカテゴリを設定し、予定ごとに色分けすることで視認性が向上します。
繰り返し予定: 毎週・毎月の繰り返し予定を自動生成する機能は、ユーザーにとって大きな利便性向上になります。
Google カレンダー連携: Expo の expo-calendar ライブラリを使えば、デバイスのネイティブカレンダーとの同期も実現できます。
まとめ
ここではRork を使ってカレンダー・スケジュール管理アプリを作る手順を解説しました。カレンダー UI の構築、予定データの CRUD 操作、AsyncStorage による永続化、そしてリマインダー通知まで、一通りの機能を実装する流れをご紹介しました。
カレンダーアプリの開発を通じて、React Native のコンポーネント設計、状態管理、データ永続化という重要なスキルを自然に身につけることができます。ぜひ、ここで学んだ内容をベースに、あなただけのオリジナルスケジュール管理アプリを完成させてみてください。