Expoを触る

Expoを使ってみる

まずは環境整備
Cursor Agent (Claude 3.5 sonnet)をゴリゴリに使う。
なので、良い.cursorrulesを見つける
Docs
このExpo公式サイトを、Cursorに「Docs」として渡す。

cursorrule探索。
ここで紹介されているExpoのルールは文字少なかったので他から見つける。
https://cursor.directory ここのExpoのコーナーにある4つから選定する。
それぞれをコピペして、Gemini 2.0 Exp 1206に投げた時のものが以下。
ここから、今回はKrish Kalariaのものを採用する。
(ちなみに、google ai studioを用いてgemini2.0flash-thining-exp0121に聞いたら、Davide Del Gattoが良いと示した。ただ、Davide Del Gatto のものはライブラリが限定され過ぎているので今回は避ける)
理由比較表
項目 | Krish Kalaria | Munyaradzi Makosa | Davide Del Gatto | Will Sims |
---|---|---|---|---|
専門分野 | TypeScript, React Native, Expo, Mobile UI | JavaScript, React Native, Expo, Mobile UI | TypeScript, React, Next.js, Expo, Tamagui, Supabase, Zod, Turbo, i18next, Zustand, React Query, Solito, Stripe | TypeScript, React Native, Expo, Mobile App Dev |
コードスタイル & 構造 | 詳細なルール、関数型、モジュール化、補助動詞使用 | クリーンコード、関数型コンポーネント、モジュール化 | 関数型、モジュール化、補助動詞使用、Tamagui準拠 | 関数型、モジュール化 |
命名規則 | 詳細 (lowercase with dashes for directories) | camelCase, PascalCase, lowercase with dashes | lowercase with dashes | camelCase, PascalCase, lowercase with dashes |
TypeScript | 厳格な使用、interface推奨、enum避ける、strictモード | PropTypes (TypeScriptを使用しない場合) | 厳格な使用、interface推奨、enum避ける、Zod併用 | 厳格な使用、interface推奨、any 避ける |
UI & スタイリング | Expoコンポーネント、Flexbox, styled-components/Tailwind CSS, Dark Mode, a11y, react-native-reanimated | 統一されたスタイリング、レスポンシブデザイン、画像最適化 | Tamagui, レスポンシブデザイン、Web/Native統一 |
StyleSheet.create() , Styled Components, レスポンシブ |
セーフエリア | 詳細な指示 (react-native-safe-area-context) | 言及なし | 言及なし (Tamaguiが対応している可能性あり) | 言及なし |
パフォーマンス最適化 | 非常に詳細 (useState/useEffectの最小化, AppLoading, SplashScreen, 画像最適化, コード分割, メモ化) | 状態管理の最適化、メモ化、FlatList最適化、匿名関数避ける | Web/Mobile両面で最適化、動的インポート、遅延読み込み、画像最適化 |
useEffect , useState の最小化, React.memo() , FlatList最適化, getItemLayout
|
ナビゲーション | react-navigation, deep linking, expo-router | Expo Router | Solito (Web/Mobile) | React Navigation |
状態管理 | React Context, useReducer, react-query, Zustand/Redux Toolkit | 状態更新の最適化、ローカルステートの適切な使用 | Zustand, React Query, 派生状態とメモ化の推奨 | 言及なし |
エラーハンドリング | 詳細 (Zod, Sentry, early return, グローバルエラー境界, expo-error-reporter) | 言及なし | 早期リターン、ガード句、カスタムエラータイプ | 言及なし |
テスト | Jest, React Native Testing Library, Detox, Expo testing tools | 言及なし | React/React Native対応のテストライブラリ | 言及なし |
セキュリティ | 詳細 (サニタイズ, react-native-encrypted-storage, HTTPS, Expo Security guidelines) | 言及なし | Supabaseのセキュリティガイドライン, Zodによるデータ検証 | 言及なし |
国際化 (i18n) | react-native-i18n/expo-localization, RTL | 言及なし | i18next (Web), expo-localization (Native) | 言及なし |
Expo固有機能 | 非常に詳細 (EAS, Updates, Permissions, AppLoading, SplashScreen, expo-constants, expo-updatesなど) | EAS Build, Updates, Expo Router | 言及少ない | EAS Build, Updates |
APIドキュメント | Expo公式ドキュメントへの参照 | Expo Routerの公式ドキュメントへの参照 | 各技術の公式ドキュメントへの準拠 | 言及なし |
その他 | Mobile Web Vitalsへの言及 | React Nativeのスレッドモデルへの理解 | Monorepo管理 (Turbo), Stripe連携, 環境変数管理, カスタムジェネレータ | |
網羅性 | 非常に高い | 中 | 特定の技術スタックに特化 | 中 |
具体性 | 非常に高い | 高 | 高 | 中 |
Expoへの最適化 | 非常に高い | 高 | 中 | 高 |

.cursorrules
cursorrules
You are an expert in TypeScript, React Native, Expo, and Mobile UI development.
Code Style and Structure
- Write concise, technical TypeScript code with accurate examples.
- Use functional and declarative programming patterns; avoid classes.
- Prefer iteration and modularization over code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
- Structure files: exported component, subcomponents, helpers, static content, types.
- Follow Expo's official documentation for setting up and configuring your projects: https://docs.expo.dev/
Naming Conventions
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
- Favor named exports for components.
TypeScript Usage
- Use TypeScript for all code; prefer interfaces over types.
- Avoid enums; use maps instead.
- Use functional components with TypeScript interfaces.
- Use strict mode in TypeScript for better type safety.
Syntax and Formatting
- Use the "function" keyword for pure functions.
- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
- Use declarative JSX.
- Use Prettier for consistent code formatting.
UI and Styling
- Use Expo's built-in components for common UI patterns and layouts.
- Implement responsive design with Flexbox and Expo's useWindowDimensions for screen size adjustments.
- Use styled-components or Tailwind CSS for component styling.
- Implement dark mode support using Expo's useColorScheme.
- Ensure high accessibility (a11y) standards using ARIA roles and native accessibility props.
- Leverage react-native-reanimated and react-native-gesture-handler for performant animations and gestures.
Safe Area Management
- Use SafeAreaProvider from react-native-safe-area-context to manage safe areas globally in your app.
- Wrap top-level components with SafeAreaView to handle notches, status bars, and other screen insets on both iOS and Android.
- Use SafeAreaScrollView for scrollable content to ensure it respects safe area boundaries.
- Avoid hardcoding padding or margins for safe areas; rely on SafeAreaView and context hooks.
Performance Optimization
- Minimize the use of useState and useEffect; prefer context and reducers for state management.
- Use Expo's AppLoading and SplashScreen for optimized app startup experience.
- Optimize images: use WebP format where supported, include size data, implement lazy loading with expo-image.
- Implement code splitting and lazy loading for non-critical components with React's Suspense and dynamic imports.
- Profile and monitor performance using React Native's built-in tools and Expo's debugging features.
- Avoid unnecessary re-renders by memoizing components and using useMemo and useCallback hooks appropriately.
Navigation
- Use react-navigation for routing and navigation; follow its best practices for stack, tab, and drawer navigators.
- Leverage deep linking and universal links for better user engagement and navigation flow.
- Use dynamic routes with expo-router for better navigation handling.
State Management
- Use React Context and useReducer for managing global state.
- Leverage react-query for data fetching and caching; avoid excessive API calls.
- For complex state management, consider using Zustand or Redux Toolkit.
- Handle URL search parameters using libraries like expo-linking.
Error Handling and Validation
- Use Zod for runtime validation and error handling.
- Implement proper error logging using Sentry or a similar service.
- Prioritize error handling and edge cases:
- Handle errors at the beginning of functions.
- Use early returns for error conditions to avoid deeply nested if statements.
- Avoid unnecessary else statements; use if-return pattern instead.
- Implement global error boundaries to catch and handle unexpected errors.
- Use expo-error-reporter for logging and reporting errors in production.
Testing
- Write unit tests using Jest and React Native Testing Library.
- Implement integration tests for critical user flows using Detox.
- Use Expo's testing tools for running tests in different environments.
- Consider snapshot testing for components to ensure UI consistency.
Security
- Sanitize user inputs to prevent XSS attacks.
- Use react-native-encrypted-storage for secure storage of sensitive data.
- Ensure secure communication with APIs using HTTPS and proper authentication.
- Use Expo's Security guidelines to protect your app: https://docs.expo.dev/guides/security/
Internationalization (i18n)
- Use react-native-i18n or expo-localization for internationalization and localization.
- Support multiple languages and RTL layouts.
- Ensure text scaling and font adjustments for accessibility.
Key Conventions
1. Rely on Expo's managed workflow for streamlined development and deployment.
2. Prioritize Mobile Web Vitals (Load Time, Jank, and Responsiveness).
3. Use expo-constants for managing environment variables and configuration.
4. Use expo-permissions to handle device permissions gracefully.
5. Implement expo-updates for over-the-air (OTA) updates.
6. Follow Expo's best practices for app deployment and publishing: https://docs.expo.dev/distribution/introduction/
7. Ensure compatibility with iOS and Android by testing extensively on both platforms.
API Documentation
- Use Expo's official documentation for setting up and configuring your projects: https://docs.expo.dev/
Refer to Expo's documentation for detailed information on Views, Blueprints, and Extensions for best practices.

Expo立ち上げ
プロジェクト名のディレクトリを作り、そこで以下のコマンドを打つ。
npx create-expo-app@latest --template blank-typescript .
(Next.jsみたいだあ)
ここでは、テンプレートとして、blank(typescript)を選択
blank テンプレートが最適な理由
シンプルなアプリ構成: このアプリは、現時点では比較的シンプルな構成のアプリです。blank テンプレートは、最小限のファイル構成から始められるため、プロジェクトの見通しが良くなります。
自由度の高さ: 必要に応じて、後から状態管理ライブラリや UI ライブラリなどを自由に追加できます。
一旦起動してみる
npx expo start
でローカル実行。表示されたQRコードを読むだけでデバックができる

AI(Cursor Agent)に開発させる前に
Expo部分の開発ドキュメントを作って、CursorAgentに渡すことで、自律的に開発をさせる。
まずは、以下のようなドキュメントを手書きで作り、CursorAgentに「このドキュメントを参考にして、あなたにこのexpo製のモバイルアプリを開発してもらいます。まずはドキュメントをよく読んで、不明点や修正が必要な点があれば教えて下さい。」と聞く。
開発ドキュメント
プロダクト概要
『お天気おかん』は、毎朝の天気予報を「お母さん」のような口調でユーザーに伝えるモバイルアプリです。ハッカソンの提出物として、必要最小限の機能を盛り込んだMVPとして高速に構築します。
用語定義
- 「お天気おかん」:アプリ日本語表示名
- 「weathermother」:ローカル開発時に使用するプロジェクト名
- 「お母さん天気情報」:APIで取得した天気予報情報をLLMで「まるでお母さんが言っているようなセリフ」に変換されたもの
実装済みの部分
現在、すでに「バックエンド」部分は完璧に実装が完了しています。
なので今回は、フロントエンド部分、モバイルアプリ部分の開発に注力します。
技術概要
バックエンド
バックエンドでは、以下の処理をバッチで毎日6時に行います。
「天気予報APIから取得した天気情報をGeminiに渡して、お母さん言葉に変換したものをfirestoreに保存」
フロントエンド
フロントエンドでは、LLMとの通信などは一切行わず、firestoreに格納されている「お母さん天気情報」を表示するシンプルな機能にします。
技術選定
バックエンド
- Cloud Functions: 天気予報APIから天気情報の取得、「お母さん天気情報」の生成、firestoreへの保存。
- Vertex AI Studio (Gemini API): 天気予報データを「おかあさんがいった」風のメッセージ(「お母さん天気情報」)に変換。
- Cloud Scheduler: Cloud Functions を定期的に実行するためのスケジューリングサービス。
- Firestore: NoSQL データベース。ユーザー情報(都道府県、プッシュ通知希望時間)、「お母さん天気情報」を保存します。
フロントエンド
- Expo(ReactNative)
開発フロー
- 環境構築
- 簡易的な画面設計
- Firebase Authによる匿名ユーザー認証機能実装
- UIの作成と基本的な画面遷移の実装
- ユーザーが都道府県を設定して、設定内容を保存する
- Firestoreのデータを参照して表示する
- プッシュ通知機能の実装
- デバッグ
- リリース準備
機能概要(フロントエンド)
「お母さん天気情報」表示機能
ユーザーがあらかじめ選択した都道府県と対応する「お母さん天気情報」を 毎日6時以降にアクセスした際に Firestoreから取得して表示する。
ユーザー認証機能
・Firebase Authentication を使用して匿名認証を実装。
・ユーザーはアプリ起動時に自動的に匿名ユーザーとしてログインする。
都道府県設定機能
・初回起動時に、ユーザーに都道府県を選択させる。
・選択された都道府県は、ユーザー情報として Firestore に保存される。
プッシュ通知
・毎日指定した時刻(例:7:00)に、ユーザーの都道府県に対応する「お母さん天気情報」メッセージをプッシュ通知で送信する。
画面構成
-
起動画面(スプラッシュスクリーン)
- アプリのアイコンと名前
- 読み込み中のインジケーター (オプション)
-
初期設定画面(初回起動時のみ)
- 「お天気おかん」の簡単な説明
- 都道府県選択用のドロップダウンリスト
- 「はじめる」ボタン (この後にプッシュ通知の許諾を求める)
-
メイン画面
- 「お母さん天気情報」の表示
- おかんのイラスト素材
- 歯車アイコン:明日とサイドメニューが開く。サイドメニューには、利用規約とプライバシーポリシーへのリンク、クレジットの表記(将来的にはアプリ内設定を行えるようにする)
データベース構造
FirestoreをDBとして使用
天気情報関連
以下の形でデータが格納済み。
weather_data/ // コレクション名
└── YYYYMMDD-areaCode/ // ドキュメントID(例:20240315-130000)
├── area_code: string // 地域コード(例:130000)
├── weather_forecasts: string // 気象庁APIからの天気予報データ(JSON文字列)
├── generated_message: string // Geminiが生成したお母さんのメッセージ
└── createdat: timestamp // データ作成日時
ユーザー情報関連
以下の形でのデータ格納を想定しています。
users/ // コレクション名
└── ユーザー ID (Firebase Authentication で生成される UID)/ // ドキュメントID
├── user_id: string // 地域コード(例:130000)
├── prefecture: string // ユーザーが選択した都道府県 (例: `tokyo`, `ehime`)
├── preferredPushNotificationTime: string // ユーザーが設定したプッシュ通知希望時刻 (例: `07:00`) (オプション機能。MVPでは使用しないが、将来のために定義しておく)
└── createdat: timestamp // ユーザー情報作成日時
サンプルデータ
{
"userId": "abcdefg1234567890",
"prefecture": "tokyo",
"preferredPushNotificationTime": "07:00",
"createdAt": "2023-10-27T09:00:00Z"
}

ドキュメント手直し
AIから差し戻しがあった箇所を補修する
AIからの差し戻し(CursorAgent)
ドキュメントを確認させていただきました。全体的によく整理されていますが、いくつか確認や検討が必要な点がありますので共有させていただきます。
技術スタックの詳細化が必要な点
Expoの開発方式(managed workflowかbare workflowか)が明記されていません
UIライブラリの選定(NativeBase、React Native Paper等)が未定です
状態管理ライブラリ(Zustand等)の選定が必要です
Firebase関連の設定詳細
Firebase SDKの具体的な設定方法やconfig情報の管理方法が未定です
Firestoreのセキュリティルールの設定方針が記載されていません
アプリのバージョニングとデプロイ
アプリのバージョン管理方針が未定です
EAS(Expo Application Services)の利用方針が明確になっていません
4. 環境変数の管理
開発環境と本番環境の切り分け方法が未定です
APIキーなどの機密情報の管理方法が記載されていません
エラーハンドリング
オフライン時の挙動
データ取得失敗時の対応
エラー表示のUI設計
テスト戦略
単体テスト、E2Eテストの方針が未定です
テストツールの選定が必要です
これらの点について、以下のような提案をさせていただきます:
技術スタックの提案
// 主要な技術スタック
- Expo Managed Workflow(シンプルな要件のため)
- React Native Paper(マテリアルデザインベースのUIライブラリ)
- Zustand(軽量な状態管理)
- expo-notifications(プッシュ通知用)
- react-native-safe-area-context(セーフエリア管理)
開発環境の整備
// 必要な開発環境 - Node.js 18以上
- Expo CLI
- Firebase CLI
- EAS CLI
ディレクトリ構成の提案
src/
├── components/ // 共通コンポーネント
├── screens/ // 画面コンポーネント
├── hooks/ // カスタムフック
├── services/ // Firebase等の外部サービス
├── types/ // 型定義
├── utils/ // ユーティリティ関数
└── constants/ // 定数
これらの点について、どのように進めていくか確認させていただけますでしょうか?また、優先順位をつけて段階的に実装を進めていくことをお勧めします。

managed workflowかbare workflowか
より
Managed Workflow
この開発フローではExpo側がネイティブコードを管理します。そのため、ビルドエラーが起きる確率が低く、安定性があります。一方、ネイティブコードを触ったり、Expo SDK以外のネイティブコードを含んだライブラリを利用できなかったりするため、細かい設定ができないというデメリットがあります。
Bare Workflow
この開発フローではユーザー側がネイティブコードを管理します。ネイティブコードを触ったり、Expo SDK以外のネイティブコードを含んだライブラリも利用でき、カスタマイズ性があります。自由度が高い分、ビルドエラーに遭遇する確率が上がります。また、Expo Goを利用できないというデメリットもあります。
基本的に「Managed Workflow」で良さそう

そのほか
- UIライブラリも状態管理ライブラリも一旦使わないことにする
- Expo Application Servicesは使ってみる