☺️
ExpoでReact Native Calendarsを使ってみた
Expo Calendar App with Bun
ExpoでカレンダーのUIを作る方法を調べていたら、React Native Calendarsというライブラリを使用すればできることを知った。
こんな感じのものを作れる。
タイムゾーンを日本時間に合わせる設定が必要で、合わせていないと日付が1日ずれていた💦
環境構築
では早速作ってみよう。
1. 前提条件
- Node.js がインストールされていること
- bun がインストールされていること
2. プロジェクトの作成
# bunを使用してExpoプロジェクトを作成
bunx create-expo-app expo-calendar -t expo-template-blank-typescript
# 必要なパッケージのインストール
bun add react-native-calendars
日本時間対応
実装のポイント
// 日本時間で現在の日付を取得
const now = new Date();
const japanTime = now.getTime() + (9 * 60 * 60 * 1000); // UTC+9の調整
const today = new Date(japanTime);
const currentDate = today.toISOString().slice(0, 10); // YYYY-MM-DD形式
// 日付フォーマット関数
const formatDate = (date: Date) => {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}年${month}月${day}日`;
};
主な特徴
- UTCからの時差計算による安定した日本時間の取得
- カスタムフォーマット関数による確実な日本語表示
- 日付の範囲エラー対策
SafeArea 対応
1. コンポーネントのインポート
import { SafeAreaView } from 'react-native';
2. 実装方法
const CalendarComponent = () => {
return (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
{/* カレンダーコンテンツ */}
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#FFFFFF' // SafeArea背景色
},
container: {
flex: 1,
padding: 20,
}
});
主な特徴
- iPhoneのノッチ部分への対応
- 適切な余白の確保
- 背景色の統一
カレンダーのカスタマイズ
1. 日本語表示
monthNames={['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']}
dayNames={['日', '月', '火', '水', '木', '金', '土']}
2. 曜日の色分け
theme={{
'stylesheet.calendar.header': {
dayTextAtIndex0: {
color: '#FF0000' // 日曜日
},
dayTextAtIndex6: {
color: '#0000FF' // 土曜日
}
}
}}
CalendarComponent.tsx
import React, { useState } from 'react';
import { View, Text, StyleSheet, SafeAreaView } from 'react-native';
import { Calendar } from 'react-native-calendars';
const CalendarComponent = () => {
// 日本時間で現在の日付を取得(修正版)
const now = new Date();
const japanTime = now.getTime() + (9 * 60 * 60 * 1000); // UTC+9の調整
const today = new Date(japanTime);
const currentDate = today.toISOString().slice(0, 10); // YYYY-MM-DD形式
// 選択された日付の状態管理
const [selected, setSelected] = useState(currentDate);
// 日付をフォーマットする関数
const formatDate = (date: Date) => {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}年${month}月${day}日`;
};
return (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
<Text style={styles.currentDate}>
現在の日付: {formatDate(today)}
</Text>
<Calendar
current={currentDate}
onDayPress={(day: { dateString: string }) => {
setSelected(day.dateString);
}}
onMonthChange={(month: {
dateString: string,
day: number,
month: number,
year: number,
timestamp: number
}) => {
console.log('月が変更されました:', month);
}}
markedDates={{
[selected]: {
selected: true,
selectedColor: '#0066CC',
},
[currentDate]: {
marked: true,
dotColor: '#FF0000',
}
}}
theme={{
todayTextColor: '#FF0000',
selectedDayBackgroundColor: '#0066CC',
arrowColor: '#0066CC',
monthTextColor: '#000000',
textMonthFontSize: 16,
textDayFontSize: 14,
'stylesheet.calendar.header': {
dayTextAtIndex0: {
color: '#FF0000' // 日曜日の色
},
dayTextAtIndex6: {
color: '#0000FF' // 土曜日の色
}
}
}}
monthNames={['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']}
dayNames={['日', '月', '火', '水', '木', '金', '土']}
/>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#FFFFFF'
},
container: {
flex: 1,
padding: 20,
},
currentDate: {
fontSize: 18,
marginBottom: 20,
textAlign: 'center',
},
});
export default CalendarComponent;
コンポーネントを読み込む。
App.tsx
import { View } from 'react-native';
import CalendarComponent from './CalendarComponent';
export default function App() {
return (
<View style={{ flex: 1 }}>
<CalendarComponent />
</View>
);
}
ビルドすると上の画像と同じUIになるはず。
今後の改善点
-
パフォーマンス最適化
- メモ化によるレンダリング最適化
- 不要な再レンダリングの防止
-
機能拡張
- 祝日表示機能
- イベント登録機能
- 複数日選択機能
-
UI/UX改善
- ダークモード対応
- アニメーション追加
- アクセシビリティ対応
トラブルシューティング
よくある問題と解決方法
-
日付の範囲エラー
- 原因: タイムゾーン設定の問題
- 解決: 適切なUTC+9の時差調整を実装
-
SafeAreaの表示問題
- 原因: スタイリングの不適切な設定
- 解決: 適切なflex設定とbackgroundColorの指定
Discussion