React Nativeでスケジュール管理アプリを作る

img

はじめに

本記事では、初心者向けに React Native を使用して スケジュール管理アプリ を作成する方法を体系的に解説します。この記事を読みながら手を動かせば、基本的なスマホアプリ開発の流れを理解できるようになります。

目次

  1. 開発環境の構築

    • 必要なツールのインストール
    • Expoのセットアップ
    • プロジェクトの作成
  2. アプリの基本構成と画面設計

    • React Navigationの導入
    • 画面の構成を決める
    • スタイルの設定(Tailwind CSS or Styled Components)
  3. スケジュール一覧画面の作成

    • FlatListを使ったリスト表示
    • ダミーデータの作成
  4. スケジュール登録・編集機能の実装

    • フォームの作成(TextInput, Button)
    • State管理(useState, useEffect)
    • スケジュールの追加・編集・削除
  5. データの永続化(AsyncStorage or Firebase)

    • AsyncStorageを使ったローカル保存
    • Firebase Firestoreを使ったクラウド保存(オプション)
  6. アプリのデザイン向上

    • アイコンやテーマカラーの設定
    • アニメーション(React Native Reanimated)
  7. アプリのテストとデバッグ

    • Expo Goを使った実機確認
    • React Developer Toolsでデバッグ
    • エラーハンドリング
  8. CI/CDとAppShotデプロイ

    • GitHub Actionsを使用したCI/CDパイプラインの構築
    • Android/iOS向けのビルド設定
    • AppShotを利用したアプリのデプロイ
    • 自動テストの実施
  9. アプリのビルドと公開

    • Google Play/App Storeへの公開

1. 開発環境の構築

必要なツールのインストール

React Native(Expo)で開発を始めるために、以下のツールをインストールします。

  • Node.js
    • バージョンはLTS (Long Term Support) が推奨です(例: 16.x / 18.x など)。
  • npm または Yarn
    • Node.js をインストールすると npm は自動的にインストールされます。
    • Yarnを使いたい場合は、別途 npm install --global yarn でインストールできます。
  • Expo CLI (もしくはCreate Expo App)
    • 以前は expo-cli をグローバルにインストールしていましたが、現在は npx または yarn create の使用が推奨されています。

Expoのセットアップ

Expoは、React Nativeの開発を簡単にするためのツールやライブラリを提供してくれます。以下のコマンドでプロジェクトを作成できます。

1
npx create-expo-app schedule-app

上記コマンド実行後、schedule-app ディレクトリが作成されます。ディレクトリに移動して依存関係をインストールしましょう。

1
2
cd schedule-app
yarn install

または

1
2
cd schedule-app
npm install

プロジェクトの作成

上記の手順を完了すると、schedule-app ディレクトリ内に App.js などの初期ファイルが作成されています。実行を確認するためには、下記コマンドを使用します。

1
npx expo start

これでブラウザの開発ツールが起動し、QRコードが表示されます。スマートフォンに Expo Go アプリをインストールしてスキャンすると、実機で動作を確認できます。


2. アプリの基本構成と画面設計

React Navigationの導入

複数画面(Screen)を切り替えるには、React Navigation がデファクトスタンダードです。以下のコマンドを実行してインストールします。

1
2
3
yarn add @react-navigation/native
yarn add @react-navigation/native-stack
yarn add react-native-screens react-native-safe-area-context

App.js(もしくは App.tsx)で基本的なスタックナビゲーションを設定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import DetailScreen from './screens/DetailScreen';

const Stack = createNativeStackNavigator();

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}

これで、HomeScreenDetailScreen の 2 画面を相互に行き来できるようになります。

画面の構成を決める

今回の「スケジュール管理アプリ」では以下のような画面構成を例とします。

  1. スケジュール一覧画面 (HomeScreen)
    • 登録されたスケジュール(リスト)の表示
    • 新規スケジュール追加ボタン
  2. スケジュール登録・編集画面 (DetailScreen)
    • スケジュールの追加・編集フォーム
    • 保存ボタン・削除ボタン

必要に応じてプロフィール設定や設定画面などを追加しても構いません。

スタイルの設定(Tailwind CSS or Styled Components)

React Nativeでのスタイリングには、以下のいずれかの方法がよく使われます。

  • Tailwind CSS (Tailwind React Native)
    • ユーティリティクラスを組み合わせることで効率的にデザインを当てられます。
  • Styled Components
    • JavaScriptファイル内でスタイルを定義できるため、コンポーネントとスタイルをひとつにまとめやすくなります。

今回はTailwind CSS(react-native-tailwindcss)を例にします。

1
yarn add twrnc

利用方法の例:

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import { View, Text } from 'react-native';
import tw from 'twrnc';

export default function HomeScreen() {
return (
<View style={tw`flex-1 justify-center items-center bg-blue-50`}>
<Text style={tw`text-lg font-bold text-blue-800`}>スケジュール一覧</Text>
</View>
);
}

3. スケジュール一覧画面の作成

FlatListを使ったリスト表示

React Native ではリストを表示する際に FlatList コンポーネントを使用します。たとえば、HomeScreen を以下のように実装します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import React from 'react';
import { View, FlatList, Text, TouchableOpacity } from 'react-native';
import tw from 'twrnc';

export default function HomeScreen({ navigation }) {
const schedules = [
{ id: '1', title: '打ち合わせ', date: '2023-01-01' },
{ id: '2', title: '資料作成', date: '2023-01-02' },
// ここにダミーデータを追加していく
];

const renderItem = ({ item }) => (
<TouchableOpacity
style={tw`p-4 bg-white border-b border-gray-200`}
onPress={() => navigation.navigate('Detail', { schedule: item })}
>
<Text style={tw`text-base font-semibold`}>{item.title}</Text>
<Text style={tw`text-gray-500 text-sm`}>{item.date}</Text>
</TouchableOpacity>
);

return (
<View style={tw`flex-1`}>
<FlatList
data={schedules}
keyExtractor={(item) => item.id}
renderItem={renderItem}
/>
<TouchableOpacity
style={tw`absolute bottom-8 right-8 bg-blue-500 p-4 rounded-full`}
onPress={() => navigation.navigate('Detail')}
>
<Text style={tw`text-white font-bold`}></Text>
</TouchableOpacity>
</View>
);
}
  • schedules: ダミーデータ。実際はデータベースやストレージから取得。
  • renderItem: 1件ごとにどのように表示するかを定義。
  • 新規追加ボタン: 画面右下に配置して、タップで「スケジュール登録・編集画面」へ遷移。

ダミーデータの作成

本格的に実装する前に、リスト表示がうまくいくか確認するためにダミーデータを複数用意します。データ構造やフィールドを固めておくと後の実装がスムーズです。


4. スケジュール登録・編集機能の実装

フォームの作成(TextInput, Button)

新規スケジュールを登録・編集する画面を作成します。DetailScreen.js(または DetailScreen.tsx)を用意して以下のように実装します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, Button, TouchableOpacity } from 'react-native';
import tw from 'twrnc';

export default function DetailScreen({ route, navigation }) {
const [title, setTitle] = useState('');
const [date, setDate] = useState('');

useEffect(() => {
if (route.params?.schedule) {
setTitle(route.params.schedule.title);
setDate(route.params.schedule.date);
}
}, [route.params?.schedule]);

const handleSave = () => {
// ここでスケジュールを保存(新規 or 編集)
// データ保存後にHomeScreenへ戻る
navigation.goBack();
};

const handleDelete = () => {
// ここでスケジュールを削除する処理
navigation.goBack();
};

return (
<View style={tw`flex-1 p-4 bg-white`}>
<Text style={tw`text-lg font-bold mb-2`}>スケジュール登録・編集</Text>

<Text style={tw`mb-1`}>タイトル</Text>
<TextInput
style={tw`border border-gray-300 p-2 mb-4`}
value={title}
onChangeText={(text) => setTitle(text)}
/>

<Text style={tw`mb-1`}>日付</Text>
<TextInput
style={tw`border border-gray-300 p-2 mb-4`}
value={date}
onChangeText={(text) => setDate(text)}
/>

<View style={tw`flex-row justify-between`}>
<Button title="保存" onPress={handleSave} />
{route.params?.schedule && (
<TouchableOpacity onPress={handleDelete} style={tw`bg-red-500 p-3 rounded`}>
<Text style={tw`text-white`}>削除</Text>
</TouchableOpacity>
)}
</View>
</View>
);
}
  • useEffectschedule パラメータがあれば、編集用として値を反映。
  • handleSave でスケジュールを保存。
  • 既存のスケジュールがある場合(編集時)のみ削除ボタンを表示。

State管理(useState, useEffect)

コンポーネント内でフォームの値を管理するために useState を使用します。画面遷移時に受け取ったデータを useEffect でセットすることで、編集モード時に既存データを表示できるようにします。

スケジュールの追加・編集・削除

本来であれば、保存や削除時にストレージやデータベースへアクセスして、HomeScreen のリストを更新する必要があります。ここでは一旦、データの永続化は考慮せず、単純に画面を戻すだけにしています。次のステップでデータの永続化を行い、実際に更新・削除されるように実装します。


5. データの永続化(AsyncStorage or Firebase)

AsyncStorageを使ったローカル保存

まずは簡易的にローカルストレージである AsyncStorage を利用します。AsyncStorage はキーと値の形でデータを保存できます。Expoプロジェクトでは、@react-native-async-storage/async-storage のインストールが必要です。

1
yarn add @react-native-async-storage/async-storage

保存処理の例

1
2
3
4
5
6
7
8
9
10
11
import AsyncStorage from '@react-native-async-storage/async-storage';

const saveSchedules = async (schedules) => {
try {
const jsonValue = JSON.stringify(schedules);
await AsyncStorage.setItem('@schedules_key', jsonValue);
} catch (e) {
// 保存に失敗した場合のエラーハンドリング
console.log(e);
}
};

取得処理の例

1
2
3
4
5
6
7
8
9
const loadSchedules = async () => {
try {
const jsonValue = await AsyncStorage.getItem('@schedules_key');
return jsonValue != null ? JSON.parse(jsonValue) : [];
} catch (e) {
console.log(e);
return [];
}
};

HomeScreenDetailScreenhandleSave / handleDelete 処理の中でこれらの関数を呼び出すことでローカル保存が可能です。

Firebase Firestoreを使ったクラウド保存(オプション)

より大規模なアプリや複数端末でデータを共有したい場合は、Firebase Firestore を使用します。Firestore の設定手順は以下の通りです。

  1. Firebase プロジェクト作成
    Firebase コンソールからプロジェクトを作成し、Firestore を有効化。

  2. React Native プロジェクトへの導入

    1
    yarn add firebase
  3. 初期化とデータの読み書き

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // firebaseConfig.js
    import { initializeApp } from 'firebase/app';
    import { getFirestore } from 'firebase/firestore';

    const firebaseConfig = {
    apiKey: "YOUR_API_KEY",
    authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
    projectId: "YOUR_PROJECT_ID",
    storageBucket: "YOUR_PROJECT_ID.appspot.com",
    messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
    appId: "YOUR_APP_ID"
    };

    const app = initializeApp(firebaseConfig);
    export const db = getFirestore(app);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 保存例
    import { collection, addDoc } from 'firebase/firestore';
    import { db } from './firebaseConfig';

    const saveScheduleToFirebase = async (title, date) => {
    try {
    await addDoc(collection(db, 'schedules'), {
    title,
    date,
    createdAt: new Date(),
    });
    } catch (e) {
    console.error('Error adding document: ', e);
    }
    };

Firestore はリアルタイムアップデート機能もあるので、複数端末での同期が必要な場合に非常に便利です。


6. アプリのデザイン向上

アイコンやテーマカラーの設定

  • Expoの場合、app.jsonexpo セクションでアプリアイコンやスプラッシュスクリーンを設定できます。
  • テーマカラーはグローバルで tailwind.config.js (またはStyled Componentsのテーマプロバイダ) で設定し、アプリ全体を通して統一するようにしましょう。

アニメーション(React Native Reanimated)

UIをよりリッチにするために、アニメーションライブラリ React Native Reanimated を利用する方法もあります。

1
yarn add react-native-reanimated

Expoの場合、babel.config.js でReanimatedプラグインを有効にするなどの手順が必要です。ボタンのフェードイン・フェードアウトや、画面の切り替え時のトランジションなどを実装できます。


7. アプリのテストとデバッグ

Expo Goを使った実機確認

エミュレータではなく、スマートフォン実機で動作を確認するには、Expo Goアプリをインストールした端末でQRコードを読み取るのが簡単です。

React Developer Toolsでデバッグ

React Developer Tools を使用すると、React Native コンポーネントツリーを視覚的に確認しながら、State などの変更をリアルタイムで追跡できます。
加えて、Chrome のデベロッパーツールのコンソールからログを確認するのも有効です。

エラーハンドリング

  • try...catch を使ってデータ保存・削除時の例外をキャッチ。
  • ネットワーク接続が必要な場合は通信エラーも考慮する。

8. CI/CDとAppShotデプロイ

GitHub Actionsを使用したCI/CDパイプラインの構築

アプリを開発していく上で、GitHub Actions などを用いてCI/CDパイプラインを組むと、自動テストやビルドが行われ、チーム開発でも効率的に運用できます。

  1. リポジトリをGitHubに作成
  2. GitHub Actionsのワークフローファイル (.github/workflows) を作成
    • プルリクエストや特定のブランチへのプッシュをトリガーに、自動ビルドやテストを実行。

たとえば、Expoのビルドを行う簡単なサンプルワークフローファイルは以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: yarn install
- name: Run tests
run: yarn test
- name: Build for production
run: yarn build

Android/iOS向けのビルド設定

  • Android: eas.json を利用してAndroid向けビルドを行います。
  • iOS: Apple Developer アカウントを用意し、EASを使って iOS ビルドを行います。

Expoの新しいビルドコマンドとして expo build は現在 expo prebuild + expo run:android / expo run:ioseas build に置き換わっています。

AppShotを利用したアプリのデプロイ

AppShot は、IPA や APK を簡単に共有・デプロイできるサービスです。以下のコマンドの通り、ビルドしたIPAファイルをアップロードしてテスターに共有できます。

1
2
export APPSHOT_DEPLOY_KEY=<デプロイキー>
/bin/bash -c "$(curl -fsSL https://app-shot.com/appshot.sh)" -m "非公開メモ" -d "説明文" test.ipa
  • APPSHOT_DEPLOY_KEY: AppShot の管理画面から発行されるデプロイキーを指定。
  • test.ipa: iOSアプリのビルド成果物(拡張子は .ipa)。

これをGitHub Actionsのワークフロー内で実行することで、自動的に最新ビルドをテスターへ配布できるようになります。

AppShotコマンドの活用例

たとえばGitHub Actionsの中に以下のようなステップを追加できます。

1
2
3
4
5
6
7
- name: Deploy to AppShot
run: |
export APPSHOT_DEPLOY_KEY=${{ secrets.APPSHOT_DEPLOY_KEY }}
/bin/bash -c "$(curl -fsSL https://app-shot.com/appshot.sh)" \
-m "iOS向けビルドの非公開メモ" \
-d "Test build for schedule app" \
build-output/ios/test.ipa

こうすることで、CI/CDのフローの最後に自動でAppShotにアップロードが行われ、テスターに配布URLを共有することでチームでの開発も可能です。
個人で開発する場合でも、USBケーブルなしにアプリが利用できるので是非お試しください。

自動テストの実施

  • ユニットテスト: Jest を使用してReactコンポーネントやロジックのテストを実施。
  • E2Eテスト: Detox などを使えば、実機に近い環境での自動テストを行うことも可能。

9. アプリのビルドと公開

Google Play/App Storeへの公開

  1. Android

    • Expo EASやAndroid Studioを使ってリリース用ビルド (.apk または .aab) を作成。
    • Google Play Console にアップロードして公開申請。
  2. iOS

    • Apple Developer Program に登録し、Expo EASやXcodeで .ipa を作成。
    • App Store Connect にアップロードして公開申請。

Expoの場合、EAS Build が推奨されます。たとえば、以下のコマンドでビルドを実行できます。

1
2
3
yarn global add eas-cli
eas build --platform ios
eas build --platform android

ビルドが完了すると、Expoの管理画面やCIのログに成果物(IPA/AAB)のリンクが表示されます。それをダウンロードしてAppShotへアップロードしテスターに配布したり、Google Play / App Storeに申請します。


まとめ

ここまで、React Native(Expo)でスケジュール管理アプリを作成する流れを以下のステップで解説してきました。

  1. 開発環境の構築
  2. アプリの基本構成と画面設計
  3. スケジュール一覧画面の作成
  4. スケジュール登録・編集機能の実装
  5. データの永続化(AsyncStorage or Firebase)
  6. アプリのデザイン向上
  7. アプリのテストとデバッグ
  8. CI/CDとAppShotデプロイ
  9. アプリのビルドと公開

最初はダミーデータを使ってリスト表示→フォーム→保存機能を実装し、その後永続化・デザイン・テスト・デプロイと段階を踏むことで、初心者でも着実に実装を進められます。特にExpoを使うことで、開発・ビルド・テストのプロセスがシンプルになるのが大きなメリットです。

React Nativeを使いこなせるようになると、1つのコードベースでiOS・Androidの両方に対応したモバイルアプリを開発できるようになります。今回のスケジュール管理アプリをきっかけに、ぜひ色々なアプリ開発に挑戦してみてください。