React Native + Expoによるモバイル開発は、Claude Codeとの相性が抜群に良いです。Expo公式がMCPサーバーとAIスキルを提供しており、Claude Codeからシミュレータの操作・EASビルドのトリガー・ExpoドキュメントのAI参照まで一気通貫で行えます。
この記事では、Expo SDK 55(2026年2月リリース)に対応した環境構築から、CLAUDE.md設計、Expo Router v7のルーティング生成、EAS Build/Updateによるデプロイまで、Claude Codeを使ったモバイル開発のフルフローを解説します。
Expo SDK 55の主要変更点
2026年2月リリースのSDK 55は、New Architecture(Fabric + TurboModules)の必須化という大きな転換点です。
| 項目 | SDK 55 |
|---|---|
| React Native | 0.83 |
| React | 19.2 |
| Expo Router | v7(ファイルベースルーティング) |
| New Architecture | 必須化(旧アーキテクチャ完全廃止) |
| Hermes v1 | opt-inで利用可能(大幅な性能改善) |
| OTAアップデート | 差分更新で約75%サイズ削減 |
| 最小iOS | 15.1 |
| Node.js | 20.19+, 22.13+, 24.3+ |
| 注目機能 | NativeTabs、Apple Zoom transition、SwiftUI/Jetpack Compose統合 |
Claude Codeでプロジェクトをセットアップする
# Expo SDK 55テンプレートで初期化 npx create-expo-app@latest MyApp --template default@sdk-55 cd MyApp # Claude Codeを起動 claude > /init
Expo MCP Serverの設定 ── シミュレータ操作からビルドまで
ExpoはClaude Code向けの公式MCPサーバーを提供しています。設定するとClaude Codeから直接以下の操作ができるようになります:
- Expoドキュメントの検索・参照
expo installによる依存パッケージ管理- EASビルドのトリガーとステータス確認
- シミュレータのスクリーンショット撮影・UI要素のタップ操作
# リモートMCPサーバーを追加 claude mcp add --transport http expo-mcp https://mcp.expo.dev/mcp # Claude Codeのプロンプトで認証 > /mcp # → Expoアカウントで認証される # ローカル機能も有効にする場合(シミュレータ操作など) npx expo install expo-mcp --dev EXPO_UNSTABLE_MCP_SERVER=1 npx expo start
EXPO_UNSTABLE_MCP_SERVER=1環境変数が必要です。Expo公式Skillsの追加
Expoは11個の公式AIスキルを提供しており、Claude Codeにインストールするとモバイル開発に特化したコンテキストが自動で補完されます。
# 利用可能なスキル(一部): # building-native-ui: ルーティング・スタイリング・アニメーション # expo-api-routes: APIルート作成 # expo-deployment: iOS/Android/Webデプロイ # expo-tailwind-setup: NativeWind + Tailwind CSS v4 # native-data-fetching: データ取得・キャッシュ・オフライン # upgrading-expo: SDKアップグレード手順 # Callstack公式のReact Nativeベストプラクティススキルも追加可能 # → JS性能最適化・ネイティブプロファイリング・バンドルサイズ削減のルール
MCPサーバーの詳しい設定はClaude Code MCP完全ガイドをご覧ください。
CLAUDE.mdテンプレート(React Native / Expo特化)
# プロジェクト名 - React Native / Expo ## 技術スタック - Expo SDK 55 (React Native 0.83, React 19.2) - New Architecture 必須 - TypeScript strict mode (any禁止) - Expo Router v7 (ファイルベースルーティング) ## スタイリング - StyleSheet.create() を基本(インラインスタイル禁止) - NativeWind v4 を併用(v5はプレリリースのため本番非推奨) ## 状態管理 - クライアント状態: Zustand - サーバー状態: TanStack Query v5 - フォーム: React Hook Form + Zod ## ナビゲーション(Expo Router v7) - src/app/(tabs)/ にタブレイアウト - src/app/(auth)/ に認証フロー - 動的ルート: [id].tsx ## コンポーネント規約 - 関数コンポーネントのみ(classコンポーネント禁止) - カスタムフック: useXxx で業務ロジックを分離 - バレルエクスポート: 各featureフォルダにindex.ts ## プラットフォーム分岐 - Platform.OS による分岐は最小限にする - .native.tsx / .ios.tsx / .android.tsx 拡張子で分離 - SafeAreaView は必ず使用 ## ディレクトリ構造 src/ app/ # Expo Router ルート components/ # 共有UIコンポーネント features/ # 機能モジュール hooks/ # カスタムフック services/ # API層 stores/ # Zustand ストア types/ # 型定義 utils/ # ユーティリティ ## テスト - コンポーネント: Jest + React Native Testing Library - テストファイル: Component.test.tsx(同一ディレクトリ配置) ## EASビルド - 開発: eas build --profile development - プレビュー: eas build --profile preview - 本番: eas build --profile production
Expo Router v7のルーティングをClaude Codeで自動生成する
Expo Router v7のファイルベースルーティングを生成してください。 画面構成: - タブ: ホーム、フィード、プロフィール - 認証: ログイン、新規登録(タブバーなし) - 商品詳細: /products/[id](動的ルート) - 設定: /settings/(スタックナビゲーション) 要件: - src/app/ 配下にファイルを配置 - (tabs)/ グループでタブレイアウト - (auth)/ グループで認証フロー - ルートレイアウトにフォント読み込みとSplashScreen制御を含める
import { Stack } from "expo-router";
import { useFonts } from "expo-font";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [fontsLoaded] = useFonts({
"Inter-Regular": require("@/assets/fonts/Inter-Regular.ttf"),
"Inter-Bold": require("@/assets/fonts/Inter-Bold.ttf"),
});
useEffect(() => {
if (fontsLoaded) SplashScreen.hideAsync();
}, [fontsLoaded]);
if (!fontsLoaded) return null;
return (
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="(auth)" options={{ headerShown: false }} />
<Stack.Screen name="products/[id]" options={{ title: "商品詳細" }} />
</Stack>
);
}
import { Tabs } from "expo-router";
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
export default function TabLayout() {
return (
<Tabs screenOptions={{ tabBarActiveTintColor: "#0284c7" }}>
<Tabs.Screen
name="index"
options={{
title: "ホーム",
tabBarIcon: ({ color }) => (
<MaterialIcons name="home" size={28} color={color} />
),
}}
/>
<Tabs.Screen
name="feed"
options={{
title: "フィード",
tabBarIcon: ({ color }) => (
<MaterialIcons name="rss-feed" size={28} color={color} />
),
}}
/>
<Tabs.Screen
name="profile"
options={{
title: "プロフィール",
tabBarIcon: ({ color }) => (
<MaterialIcons name="person" size={28} color={color} />
),
}}
/>
</Tabs>
);
}
状態管理とAPI連携の自動生成
2026年のReact Nativeモバイル開発では、Zustand(クライアント状態)+ TanStack Query(サーバー状態)の組み合わせが主流です。
以下の状態管理を実装してください。 1. src/stores/useAuthStore.ts (Zustand) - user, token を管理 - setAuth, logout アクション - AsyncStorageに永続化 2. src/hooks/useProducts.ts (TanStack Query) - 商品一覧取得: useProducts() - 商品詳細取得: useProduct(id) - ページネーション対応 - エラー時のリトライ設定(3回)
import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware";
import AsyncStorage from "@react-native-async-storage/async-storage";
interface User {
id: string;
name: string;
email: string;
}
interface AuthState {
user: User | null;
token: string | null;
setAuth: (user: User, token: string) => void;
logout: () => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
user: null,
token: null,
setAuth: (user, token) => set({ user, token }),
logout: () => set({ user: null, token: null }),
}),
{
name: "auth-storage",
storage: createJSONStorage(() => AsyncStorage),
}
)
);
import { useQuery } from "@tanstack/react-query";
import { useAuthStore } from "@/stores/useAuthStore";
const API_URL = process.env.EXPO_PUBLIC_API_URL;
async function fetchJSON<T>(path: string, token: string | null): Promise<T> {
const res = await fetch(`${API_URL}${path}`, {
headers: token ? { Authorization: `Bearer ${token}` } : {},
});
if (!res.ok) throw new Error(`API Error: ${res.status}`);
return res.json();
}
export function useProducts(page = 1) {
const token = useAuthStore((s) => s.token);
return useQuery({
queryKey: ["products", page],
queryFn: () => fetchJSON(`/products?page=${page}`, token),
retry: 3,
});
}
export function useProduct(id: string) {
const token = useAuthStore((s) => s.token);
return useQuery({
queryKey: ["product", id],
queryFn: () => fetchJSON(`/products/${id}`, token),
enabled: !!id,
});
}
EAS Build / UpdateでCI/CDを構築する
eas.jsonの設定
{
"cli": { "version": ">= 14.0.0" },
"build": {
"base": {
"node": "22.13.0",
"env": { "EXPO_PUBLIC_API_URL": "https://api.example.com" }
},
"development": {
"extends": "base",
"developmentClient": true,
"distribution": "internal",
"android": { "buildType": "apk" },
"ios": { "simulator": true }
},
"preview": {
"extends": "base",
"distribution": "internal"
},
"production": {
"extends": "base",
"autoIncrement": true
}
},
"submit": {
"production": {
"android": { "track": "internal" },
"ios": {
"appleId": "your@email.com",
"ascAppId": "1234567890",
"appleTeamId": "AB12XYZ34S"
}
}
}
}
# 開発ビルド > eas build --profile development --platform ios を実行してください # 本番ビルド + ストア申請 > eas build --profile production --platform all を実行し、 > 完了後に eas submit --platform all でストアに申請してください # OTAアップデート(ストア審査なしで即時配布) > eas update --branch production --message "ログイン画面のバグ修正"
EAS WorkflowsでCI/CDを自動化
name: Build and Submit
on:
push:
branches: ["main"]
jobs:
build_android:
type: build
params:
platform: android
profile: production
build_ios:
type: build
params:
platform: ios
profile: production
submit_android:
type: submit
needs: [build_android]
params:
build_id: ${{ needs.build_android.outputs.build_id }}
submit_ios:
type: submit
needs: [build_ios]
params:
build_id: ${{ needs.build_ios.outputs.build_id }}
テストコードの自動生成
src/components/LoginButton.tsxに対するテストを書いてください。 テスト対象: - ログインボタンが表示されること - タップでonPressが呼ばれること - loading=true のとき disabled + ActivityIndicator 表示 - React Native Testing Library を使用
import { render, screen, fireEvent } from "@testing-library/react-native";
import { LoginButton } from "../LoginButton";
describe("LoginButton", () => {
it("ログインボタンが表示される", () => {
render(<LoginButton onPress={() => {}} />);
expect(screen.getByText("ログイン")).toBeTruthy();
});
it("タップでonPressが呼ばれる", () => {
const onPress = jest.fn();
render(<LoginButton onPress={onPress} />);
fireEvent.press(screen.getByText("ログイン"));
expect(onPress).toHaveBeenCalledTimes(1);
});
it("loading時はdisabledでスピナー表示", () => {
render(<LoginButton onPress={() => {}} loading />);
expect(screen.getByTestId("loading-indicator")).toBeTruthy();
expect(screen.queryByText("ログイン")).toBeNull();
});
});
テスト戦略全般についてはClaude Codeテスト完全ガイドもあわせてご覧ください。
よくある質問
expo installなどの基本機能は無料プランでも使えます。EASビルドのトリガーやテストフライトデータの取得にはEAS有料プランが必要です。@react-navigation/*) は直接使用しない」と明記してください。Expoの公式AIスキルをインストールすると、最新のExpo RouterのAPIが参照されるようになります。.eas/workflows/)がExpo公式推奨です。ビルド環境(Xcode/Gradle)をExpo側が管理してくれるため、自前のCI環境構築が不要になります。ただし、EASのビルドクレジットに制限があるため、コスト管理が必要です。GitHub Actionsも引き続きサポートされており、expo/expo-github-action@v8で連携可能です。まとめ
Claude Code × React Native(Expo)のモバイル開発で押さえるべきポイントをまとめます。
- Expo MCP Serverで直接操作: シミュレータ操作・EASビルド・ドキュメント参照がClaude Codeから直接可能
- CLAUDE.mdにReact Native規約を明記: Expo Router v7・NativeWind v4・Zustand + TanStack Queryの設定を書いておくと正しいパターンで生成される
- Expo Router v7でルーティング自動生成: ファイルベースルーティング・タブ・認証フローをプロンプトから一括生成
- EAS Workflowsで自動CI/CD: ビルド→ストア申請→OTAアップデートの全フローを自動化
- テストも自動生成: Jest + React Native Testing Libraryのテストコードをコンポーネントと同時に生成させる
Claude Codeの全体的なワークフローはClaude Codeワークフロー完全ガイド、MCPの設定はClaude Code MCP完全ガイドをご覧ください。

