Claude Code × React Native / Expo モバイル開発完全ガイド|MCP連携・CLAUDE.mdテンプレート・Expo Router v7・EAS Build自動化【2026年最新】

Claude Code × React Native / Expo モバイル開発完全ガイド|MCP連携・CLAUDE.mdテンプレート・Expo Router v7・EAS Build自動化【2026年最新】 AI開発

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要素のタップ操作
Expo MCP Serverの追加
# リモート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 MCP Serverの利用にはExpoアカウントとEAS有料プランが必要です。ローカルのシミュレータ操作機能はEXPO_UNSTABLE_MCP_SERVER=1環境変数が必要です。

Expo公式Skillsの追加

Expoは11個の公式AIスキルを提供しており、Claude Codeにインストールするとモバイル開発に特化したコンテキストが自動で補完されます。

Expo Skillsの主要なもの
# 利用可能なスキル(一部):
# 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特化)

CLAUDE.md テンプレート
# プロジェクト名 - 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
CLAUDE.mdに技術スタックとディレクトリ構造を明記しておくと、Claude Codeが新しいファイルを正しい場所に生成し、正しいパターン(Expo Router v7記法、Zustandストア等)で書いてくれます。

Expo Router v7のルーティングをClaude Codeで自動生成する

ルーティング生成プロンプト
Expo Router v7のファイルベースルーティングを生成してください。

画面構成:
- タブ: ホーム、フィード、プロフィール
- 認証: ログイン、新規登録(タブバーなし)
- 商品詳細: /products/[id](動的ルート)
- 設定: /settings/(スタックナビゲーション)

要件:
- src/app/ 配下にファイルを配置
- (tabs)/ グループでタブレイアウト
- (auth)/ グループで認証フロー
- ルートレイアウトにフォント読み込みとSplashScreen制御を含める
生成されるルートレイアウト(src/app/_layout.tsx)
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>
  );
}
タブレイアウト(src/app/(tabs)/_layout.tsx)
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回)
生成されるZustandストア
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),
    }
  )
);
TanStack Queryのカスタムフック
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の設定

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"
      }
    }
  }
}
Claude Codeにビルド・デプロイを依頼
# 開発ビルド
> 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を自動化

.eas/workflows/build-and-submit.yml
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 }}
EAS Workflowsは2026年のExpo推奨CI/CDです。GitHub Actionsに比べてビルド環境の管理が不要で、Expoのエコシステムと完全統合されています。

テストコードの自動生成

テスト生成プロンプト
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テスト完全ガイドもあわせてご覧ください。

よくある質問

QExpo MCP Serverは無料で使えますか?
AExpoアカウントは必要ですが、ドキュメント検索やexpo installなどの基本機能は無料プランでも使えます。EASビルドのトリガーやテストフライトデータの取得にはEAS有料プランが必要です。
QClaude Codeが古いReact Navigationのコードを生成します。どうすれば防げますか?
ACLAUDE.mdに「Expo Router v7ファイルベースルーティングを使用。React Navigation (@react-navigation/*) は直接使用しない」と明記してください。Expoの公式AIスキルをインストールすると、最新のExpo RouterのAPIが参照されるようになります。
QNativeWind v4とv5のどちらを使うべきですか?
A2026年3月時点ではv4が安定版で本番利用に推奨です。v5はTailwind CSS v4ベースでCSS変数やP3カラーに対応しますがプレリリース段階です。新規プロジェクトで試験的に使うのは問題ありませんが、本番アプリにはv4を選んでください。
QEAS BuildとGitHub Actionsのどちらを使うべきですか?
AEAS Workflows(.eas/workflows/)がExpo公式推奨です。ビルド環境(Xcode/Gradle)をExpo側が管理してくれるため、自前のCI環境構築が不要になります。ただし、EASのビルドクレジットに制限があるため、コスト管理が必要です。GitHub Actionsも引き続きサポートされており、expo/expo-github-action@v8で連携可能です。
QReact NativeとFlutterのどちらを選ぶべきですか?
AClaude Codeとの連携を重視するならReact Native(Expo)が有利です。ExpoがMCPサーバー・公式Skillを提供しており、Claude CodeがExpoのエコシステムに直接アクセスできます。FlutterにはこのレベルのAIツール統合はまだありません(2026年3月時点)。

まとめ

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完全ガイドをご覧ください。